c# - 在 .NET 中将属性公开为变体以进行互操作

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

我正在 .NET(碰巧是 VB.NET,但与 C# 同样相关)中创建一个包装类,它向 COM 公开,我试图包装的属性之一是 Variant。我以为我只能使用一个对象,但我得到了一个错误:

Public Property FieldValue([vFieldID As Object = -1]) As Object cannot be exposed to COM as a property 'Let'. You will not be able to assign non-object values (such as numbers or strings) to this property from Visual Basic 6.0 using a 'Let' statement.*

我的属性(property)声明如下所示:

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 接口(interface)将 Fields 属性作为默认属性,生成一个 Fields 接口(interface)引用。它具有 Item 属性作为生成 Field 接口(interface)引用的默认(索引)属性。它具有 Value 属性作为默认属性,产生一个变体。

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

Dim obj  
obj = someObject

这里的目的是什么?您要将 someObject 引用分配给 obj 吗?还是要分配 someObject 的默认属性?非常不同的东西,obj 类型会完全不同。这已在 VB6 中使用 Set 关键字解决。如果你想分配对象引用,那么你必须写:

Set obj = someObject

如果您要分配默认属性值,则可以省略 Set 或显式使用 Let。这太令人讨厌了,长期以来一直困扰着新手 Visual Basic 和 VB 脚本程序员。

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

Zip forward 到 VB.NET,Microsoft 认为歧义太痛苦,因此取消了默认非索引属性的概念。这也幸福地淘汰了 Set 关键字。然而,这会产生一个新问题,不再有任何方法可以编写一个 [ComVisible] 类,该类可以具有 Object 类型的属性和接受对象引用的 setter。语言语法只允许一个 setter,而 CLR 中的 COM 互操作层缺少合成两个的管道。值得注意的是,这只是一个警告,您仍然可以获得 propput setter,只是不会获得 propputref setter。据我所知,这正是您想要的。

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

关于c# - 在 .NET 中将属性公开为变体以进行互操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9481140/

相关文章:

c# - 十进制三进制不起作用

c# - 如何编译单声道源代码

mysql - 多段线无法绑定(bind)

asp.net-mvc - 使用 AWS .NET SDK 确认 SNS 订阅的示例

c# - C# 枚举条目的名称中可以包含连字符吗

c# - 为什么 Visual Studio 将新创建的数组键入为可空?

asp.net - Visual Basic 编译器 (vbc.exe) 用完所有系统内存(RAM 和虚拟)

c# - COM 互操作、C#、Visual Studio 2010 -> 嵌入互操作类型

c++ - 转换 DirectX 接口(interface)

c# - 使用 COM 从注册表加载类适用于 ToolsVersion ="2.0"但因 ToolsVersion ="4.0"而失败