我看到很多初学者(可能是受了某人的书的影响),在用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)使用自定义的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吧。
能否针对此举例。
variant为什么占用内存大,你的通过接口传有什么优缺点。
通过接口传递是COM的标准做法。
VARIANT这种类型本身占用内存大,速度慢(======是有点影响,但绝对没这么严重======)。而且只支持标准类型,很难支持自定义的参数类型(======决大多数类型都可以转换为VARIANT,对于一般应用来说,足够了======)。
特别的。以前在DELPHI里有个经典的问题,很多人都问,怎么在COM里传出一个ado的Recordset出来。当时很多人都发现无法使用VARIANT来传这个东西(======为什么啊,可以的啊=====)。但是其实很简单,用一个IUnknown类型就可以传出来了。因为Recordset就是一个接口类型。:)
对于一个客户程序来说,少点效率没什么关系。但对于服务器端来说,是不可接受的。
通常会使用大量自定义类型。VARIANT根本很难满足。
你通过接口传递数据不同样需要scm来管理,同样有时空的开销啊。
你的意思是否是这样,通过接口把数据传进去,如你的IPacket肯定是有个set_length。
然后你在调用了set_length后,然后再通过另一个接口调用得到参数。
请问我在传递大量复杂数据时该怎么办,比如说是一个数据集。
2)任何传递数据当然是要有开销的,我的意思是用接口传递会比用VARIANT效率高。答案看我上面的回答。
3)我不知道你们到底是怎么写程序的?一般来说,一个合格的面向对象的程序员,会在系统中包装很多自己定义的接口对象。比如我要传递一个货物的数据集,我就会定义这个货物为一个对象,包含他所有的属性,然后作为接口传递。
TSomething = class(TMyParent, ISomething)
.....
end;
然后在传递参数时作为接口ISomething 传递给COM接口方法。peiweiwei你上面那样问,给我的感觉就是你在写程序时完全没有自定义对象,你的程序不是面向对象的。所以才会那样问。:)
你这句话我没看懂您的意思。一般来说,无论是否对象,只要是块内存区,谁产生它的,就由谁来释放。而不存在两端都要维护的可能性。 如何设计数据集对象,已经超出本贴的范围。如果你有兴趣,可以另外开贴讨论。:)
我建议您可以看看这篇文章(MS推荐必看) 《业务对象映射到关系数据库的若干模式》
http://www.oone.com.cn/article/oorpat.htm
http://www.microsoft.com/china/msdn/library/dnbda/html/BOAGag.asp
对于一个客户程序来说,少点效率没什么关系。但对于服务器端来说,是不可接受的(呵呵,现在我们的系统不是运行得好好的吗,我觉得用VARIANT对效率几乎没什么影响的)。
通常会使用大量自定义类型。VARIANT根本很难满足(======自定义类型也可以转化为VARIANT啊=========)。
TSomething = class(TMyParent, ISomething)
.....
end;
能否请楼主提供更多的理论依据,就如同你提供的那几篇文章一样。
楼主发贴的目的可能是给大家提个醒另外提供一个讨论的机会。
但是我觉得你说的笼统了点,其实我是部分同意你的观点的,而且也在积极配合你的讨论。但苦于没有实际的构建经验,说起variant其实我就只用过olevariant,楼主能否针对variant的目标和优缺点。另外再结合项目进度,易用性等方面做一个系统的评价。不能因为variant占用内存过大就把它一棍子打死,这也是我试图反驳你的原因所在。
另外没有必要因为MIDAS用了VARIANT,你也跟风。MIDAS用它是为了使MIDAS比较通用,方便一些人使用而已。而并不是说VARIANT很好。我要说的就这么多。是是非非大家自己判断。我只根据我的经验给大家提醒而已。:)
1,关于效率.离开特定环境,具体项目谈效率只是空对空的。要跟踪实现运行情况,
拿数据说话。特别在具体项目中,涉及因素太多,此消彼长,不能一概而论。。
2,关于variant的使用,则见仁见智。
至少它是调用间弱化类型的一个重要工具,在一个大型的,复杂的系统中,
仅拿软件来说,就有’硬‘有’软‘,有些部分需要做成硬硬的组件,有些适宜写
成脚本,运行时候随时就改。。变体类型,也就是Variant型在里面功劳不小。