Interop中将属性公开为.NET中的变体

我正在.NET中创建一个包装类(VB.NET,因为它发生但与C#同样相关),它暴露给COM,我试图包装的其中一个属性是Variant。 我以为我只能使用一个Object,但是我收到一个错误:

Public Property FieldValue([vFieldID As Object = -1]) As Object不能作为属性’Let’向COM公开。 您将无法使用“Let”语句从Visual Basic 6.0为此属性分配非对象值(如数字或字符串)。*

我的财产声明如下:

 Public Property FieldValue(Optional ByVal vFieldID As Object = -1) As Object Get Return _objVAccess.FieldValue(vFieldID) End Get Set(ByVal value As Object) _objVAccess.FieldValue = value End Set End Property 

我的属性实际上从数据库返回一个值,该值可以是整数,字符串,日期等,因此它不是 COM方面的对象。 是否有任何解决方法允许属性让?

COM Automation支持一个默认属性,即具有dispid 0的属性。这在VB6代码中使用效果很好,生成非常紧凑的代码。 一个典型的例子是:

 rs!Customer = "foo" 

这是语法糖:

 rs.Fields.Item("Customer").Value = "foo" 

此处使用了三个默认属性,但未在原始语句中进行命名。 Recordset接口将Fields属性作为默认属性,生成Fields接口引用。 其中Item属性作为默认(索引)属性,生成Field接口引用。 其中Value属性作为默认属性,生成变体。

哪个非常好。 然而,像这样的极端语法糖的价格是蛀牙。 在语句中存在语法歧义,例如:

 Dim obj obj = someObject 

这是什么意思? 是否要将someObject引用分配给obj? 或者您想要分配someObject的默认属性 ? 非常不同的东西, obj类型将完全不同。 这是在VB6中使用Set关键字解决的。 如果要分配对象引用,则必须编写:

 Set obj = someObject 

如果您要分配默认属性值,则省略Set或use Let 。 这很令人讨厌,并且已经困扰了新手Visual Basic和VB脚本程序员很长一段时间。

COM Automation通过允许属性具有两个 setter来实现此function。 IDL中的propputpropputref分别是propputref是指定对象的那个。 您还可以在IDispatch定义中看到这一点,IDispatch :: Invoke()方法使用DISPATCH_PROPERTYPUT和DISPATCH_PROPERTYPUTREF区分两者。

向前推进到VB.NET,微软认为模糊性太痛苦并且消除了默认的非索引属性的概念。 哪个幸福也退休了Set关键字。 然而,这会产生一个新问题,没有任何方法可以编写一个[ComVisible]类,它可以具有Object类型的属性,并且具有接受对象引用的setter。 语言语法只允许一个setter,CLR中的COM interop层缺少合成两个的管道。 值得注意的是,这只是一个警告,你仍然得到了propput setter,你只是不会得到propputref setter。 据我所知,无论如何都是你想要的。

在VB6虚拟类中定义接口,或者通过显式写入IDL并使用midl.exe编译它确实是一种绕过警告的方法。 如约翰里瓦德在这个问题中所示 。

您是否尝试使用MarshalAs属性?

你应该可以这样应用它(抱歉,如果我有语法错误,我通常使用C#):

 Public Property FieldValue(Optional ByVal vFieldID As Object = -1) As  Object Get Return _objVAccess.FieldValue(vFieldID) End Get Set(ByVal value As Object) _objVAccess.FieldValue = value End Set End Property 

这应该告诉编组人员将属性暴露为VARIANT结构。

您可能必须为结构大小等应用其他属性,但我认为这是您可以用来解决问题的方向。