我看到很多初学者(可能是受了某人的书的影响),在用COM写程序的时候,在传递一些TYPELIB编辑器未定义的类型作为参数时,总是喜欢使用VARIANT来作为参数。这个虽然没什么错误,但是是个不好的习惯。  VARIANT这种类型本身占用内存大,速度慢。而且只支持标准类型,很难支持自定义的参数类型。所以大家如果有自定义的参数类型要传递给COM方法时,建议大家使用如下方式:
 1)使用自定义的interface,该interface当然是从Iunknown或者IDispatch继承下来的。为他们定义自己的属性,然后作为参数传递,就可以达到目的。例如:   HRESULT _stdcall SendPacket([in] IPacket * pPacket);  该例子用一个自定义的IPacket接口作为参数来传递。
  IPacket = interface(IUnknown)
    ['{678F2D1B-5D36-4AB8-AB35-DA09788D3150}']
    function Clear: HResult; stdcall;
    function Get_Length(out pVal: Integer): HResult; stdcall;
  end;特别的。以前在DELPHI里有个经典的问题,很多人都问,怎么在COM里传出一个ado的Recordset出来。当时很多人都发现无法使用VARIANT来传这个东西。但是其实很简单,用一个IUnknown类型就可以传出来了。因为Recordset就是一个接口类型。:)2)如果你不想使用接口,想使用完全自定义的类型,比如你自己定义的一个指针对象。可以使用void*这种方式(注意这种方式不能在DCOM里使用)
  HRESULT _stdcall AddData([in] void * pDataAddRess, [in] long Len );delphi把void*解析成pointer这种无类型指针。注意,大家可以查看下编辑器生成的IDL代码,其实DELPHI是省略了[local]表示符。MS定义的标准方式其实应该是: [local][helpstring("method GetData")] HRESULT GetData([out,retval] void* pDataAddRess); 前面有个[local]符号,表示这是本地调用。希望对大家有用。赶快抛弃没用的VARIANT吧。

解决方案 »

  1.   

    以前在DELPHI里有个经典的问题,很多人都问,怎么在COM里传出一个ado的Recordset出来。当时很多人都发现无法使用VARIANT来传这个东西。但是其实很简单,用一个IUnknown类型就可以传出来了。因为Recordset就是一个接口类型。
    能否针对此举例。
      

  2.   

    上面的问题我理解了,能否讲解一下
    variant为什么占用内存大,你的通过接口传有什么优缺点。
      

  3.   

    variant类型占用16个字节。而普通指针只是4字节而已。相差了4倍!并且在使用过程中variant还需要做类型转换。
    通过接口传递是COM的标准做法。
      

  4.   

    有些观点不敢苟同,提出些不同意见供参考我使用了很长时间这个VARIANT了,觉得对于复杂应用来说,是非常理想的一种类型
    VARIANT这种类型本身占用内存大,速度慢(======是有点影响,但绝对没这么严重======)。而且只支持标准类型,很难支持自定义的参数类型(======决大多数类型都可以转换为VARIANT,对于一般应用来说,足够了======)。

    特别的。以前在DELPHI里有个经典的问题,很多人都问,怎么在COM里传出一个ado的Recordset出来。当时很多人都发现无法使用VARIANT来传这个东西(======为什么啊,可以的啊=====)。但是其实很简单,用一个IUnknown类型就可以传出来了。因为Recordset就是一个接口类型。:)
      

  5.   

    freekany2002有不同意见是好的。:)
    对于一个客户程序来说,少点效率没什么关系。但对于服务器端来说,是不可接受的。
    通常会使用大量自定义类型。VARIANT根本很难满足。
      

  6.   

    通过接口传递是COM的标准做法?
    你通过接口传递数据不同样需要scm来管理,同样有时空的开销啊。
    你的意思是否是这样,通过接口把数据传进去,如你的IPacket肯定是有个set_length。
    然后你在调用了set_length后,然后再通过另一个接口调用得到参数。
    请问我在传递大量复杂数据时该怎么办,比如说是一个数据集。
      

  7.   

    1)通过接口传递是COM的标准做法
    2)任何传递数据当然是要有开销的,我的意思是用接口传递会比用VARIANT效率高。答案看我上面的回答。
    3)我不知道你们到底是怎么写程序的?一般来说,一个合格的面向对象的程序员,会在系统中包装很多自己定义的接口对象。比如我要传递一个货物的数据集,我就会定义这个货物为一个对象,包含他所有的属性,然后作为接口传递。
      TSomething = class(TMyParent, ISomething)
      .....
      end;
    然后在传递参数时作为接口ISomething 传递给COM接口方法。peiweiwei你上面那样问,给我的感觉就是你在写程序时完全没有自定义对象,你的程序不是面向对象的。所以才会那样问。:)
      

  8.   

    一般来讲我都是使用远程数据模块,现在接手的一个项目也是第一次考虑直接使用com技术,是个c/s模式的软件。因为要考虑到升级的问题。虽然我们设计呢也是采用的oo的方法,但如何看待和处理数据集是我一直头痛的问题。你通过对象传递的方法,无非是传递了一个指针,你能够处理这个对象的前提是,你必须在客户端和组件中同时维护这个对象。试问我是维护一个无状态的variant好还是维护一个有状态的对象好呢?我本来只是传一个数据,现在变成维护一个对象。
      

  9.   

    不对。有状态和无状态的区别不是由是否是VARIANT来决定的。VARIANT一样也有可能是有状态的,指针对象一样可以是无状态的。一般来说,作为面向对象设计方式,直接返回RecordSet在自己的业务逻辑里,是不被赞成的。MS有一套固定的开发模型,我不知道你研究过没有。可以用来解决这个问题。》》你必须在客户端和组件中同时维护这个对象。
    你这句话我没看懂您的意思。一般来说,无论是否对象,只要是块内存区,谁产生它的,就由谁来释放。而不存在两端都要维护的可能性。   如何设计数据集对象,已经超出本贴的范围。如果你有兴趣,可以另外开贴讨论。:)
       我建议您可以看看这篇文章(MS推荐必看)   《业务对象映射到关系数据库的若干模式》
       http://www.oone.com.cn/article/oorpat.htm
      

  10.   

    不好意思,上面的连接给错了。:) 不过那篇也是篇好文章。《设计数据层组件并在层间传递数据》
    http://www.microsoft.com/china/msdn/library/dnbda/html/BOAGag.asp
      

  11.   

    freekany2002有不同意见是好的。:)
    对于一个客户程序来说,少点效率没什么关系。但对于服务器端来说,是不可接受的(呵呵,现在我们的系统不是运行得好好的吗,我觉得用VARIANT对效率几乎没什么影响的)。
    通常会使用大量自定义类型。VARIANT根本很难满足(======自定义类型也可以转化为VARIANT啊=========)。
      

  12.   

    3)我不知道你们到底是怎么写程序的?一般来说,一个合格的面向对象的程序员,会在系统中包装很多自己定义的接口对象。比如我要传递一个货物的数据集,我就会定义这个货物为一个对象,包含他所有的属性,然后作为接口传递(===是这样吗,我觉得你需要好好看一下MIDAS的数据传输方式--》用的就是VARIANT类型啊,===)。
      TSomething = class(TMyParent, ISomething)
      .....
      end;
      

  13.   

    还有不要忘记一点,VARIANT存在的理由是因为后期编译的需要!
      

  14.   

    我觉得楼主的想法是很有用的,但大家用variant惯了。
    能否请楼主提供更多的理论依据,就如同你提供的那几篇文章一样。
    楼主发贴的目的可能是给大家提个醒另外提供一个讨论的机会。
    但是我觉得你说的笼统了点,其实我是部分同意你的观点的,而且也在积极配合你的讨论。但苦于没有实际的构建经验,说起variant其实我就只用过olevariant,楼主能否针对variant的目标和优缺点。另外再结合项目进度,易用性等方面做一个系统的评价。不能因为variant占用内存过大就把它一棍子打死,这也是我试图反驳你的原因所在。
      

  15.   

    veryok: 我想你可以看看WINDOWS定义的VARIANT到底是个什么样的类型,你就会了解到效率上的差别。要知道,查看效率不能凭人的感觉来做的。:)另外VARIANT也不是什么后期编译的需要,他只是在运行时自动转换成相应的类型。只是DELPHI把这些都屏蔽了,你看不到而已。
    另外没有必要因为MIDAS用了VARIANT,你也跟风。MIDAS用它是为了使MIDAS比较通用,方便一些人使用而已。而并不是说VARIANT很好。我要说的就这么多。是是非非大家自己判断。我只根据我的经验给大家提醒而已。:)
      

  16.   

    什么事情都不是绝对的,基本上VARIANT和接口的区别有点类似于C中void *和typed *的区别,void *不推荐使用,不表示它完全不能用,要看具体情况。
      

  17.   

    有不同看法:
    1,关于效率.离开特定环境,具体项目谈效率只是空对空的。要跟踪实现运行情况,
    拿数据说话。特别在具体项目中,涉及因素太多,此消彼长,不能一概而论。。
    2,关于variant的使用,则见仁见智。
    至少它是调用间弱化类型的一个重要工具,在一个大型的,复杂的系统中,
    仅拿软件来说,就有’硬‘有’软‘,有些部分需要做成硬硬的组件,有些适宜写
    成脚本,运行时候随时就改。。变体类型,也就是Variant型在里面功劳不小。
      

  18.   

    是啊,对于ASP调用来说,除了OleVariant,它还真不认其它类型。