在.NET中为Interop公开属性作为变体

时间:2012-02-28 11:35:09

标签: c# vb.net com properties com-interop

我正在.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对象。是否有任何解决方法允许属性Let?

2 个答案:

答案 0 :(得分:30)

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 或明确使用 Let 。这非常令人讨厌,并且长期困扰新手Visual Basic和VB脚本程序员。

COM Automation通过允许属性具有两个 setter来实现此目的。在IDL中分别是 propput propputref ,其中propputref是分配对象的那个。还可以看到这早在IDispatch的定义中,的IDispatch :: invoke()方法在两个与DISPATCH_PROPERTYPUT和DISPATCH_PROPERTYPUTREF之间进行区分。

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

在VB6虚拟类中定义接口,或者通过显式写入IDL并使用midl.exe编译它确实是一种绕过警告的方法。正如John Rivard在this question中所示。

答案 1 :(得分:3)

您是否尝试使用MarshalAs属性?

你应该能够像那样应用它(抱歉,如果我有语法错误,我通常使用C#):

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

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

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