在 .NET 中为互操作公开属性作为变体 [英] Exposing Property as Variant in .NET for Interop

查看:20
本文介绍了在 .NET 中为互操作公开属性作为变体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 .NET 中创建一个包装类(实际上是 VB.NET,但与 C# 同样相关),该包装类暴露给 COM,我试图包装的属性之一是 Variant.我以为我只能使用对象,但出现错误:

I am creating a wrapper class in .NET (VB.NET as it happens but is equally related to C#) that is exposed to COM and one of the properties I am trying to wrap is a Variant. I thought I would just be able to use an Object, but I get an error:

公共属性 FieldValue([vFieldID As Object = -1]) As Object 不能作为属性Let"公开给 COM.您将无法使用Let"语句从 Visual Basic 6.0 将非对象值(例如数字或字符串)分配给此属性.*

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.*

我的属性声明如下所示:

My property declaration looks like this:

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?

My property actually returns a value from the database which can be integer, string, date, etc so it isn't an object in terms of COM. Is there any workaround to this to allow property Let?

推荐答案

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

COM Automation supports a default property, the property that has dispid 0. This is used in VB6 code to great effect, generating really compact code. A typical example is:

rs!Customer = "foo"

语法糖用于:

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

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

Three default properties being used here without being named in the original statement. The Recordset interface has the Fields property as the default property, producing a Fields interface reference. Which has the Item property as the default (indexed) property producing a Field interface reference. Which has the Value property as the default property, producing a variant.

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

Which is very nice. The price of extreme syntax sugar like this however is tooth decay. There's a syntax ambiguity in a statement like:

Dim obj  
obj = someObject

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

What is intended here? Do you want to assign the someObject reference to obj? Or do you want to assign the default property of someObject? Very different things, the obj type will be completely different. This was solved in VB6 with the Set keyword. If you want to assign the object reference then you have to write:

Set obj = someObject

如果您想分配默认属性值,则可以省略 Set 或显式使用 Let.这太恶心了,并且困扰了 Visual Basic 和 VB 脚本程序员很长一段时间.

And you omit Set or use Let explicitly if you mean to assign the default property value. That's pretty yucky and has bedeviled newbie Visual Basic and VB script programmers for a very long time.

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

COM Automation implements this by allowing a property to have two setters. Respectively propput and propputref in the IDL where propputref is the one that assigns an object. You can also see this back in the IDispatch definition, the IDispatch::Invoke() method distinguishes between the two with DISPATCH_PROPERTYPUT and DISPATCH_PROPERTYPUTREF.

转至 VB.NET,Microsoft 认为这种歧义太痛苦,并消除了默认非索引属性的概念.令人高兴的是,也取消了 Set 关键字.然而,这产生了一个新问题,没有任何方法可以编写一个 [ComVisible] 类,该类可以具有一个 Object 类型的属性,并带有一个接受对象引用的 setter.语言语法只允许一个 setter,而 CLR 中的 COM 互操作层缺少合成两个 setter 的管道.值得注意的是,这只是一个警告,你仍然会得到 propput setter,你只是不会得到 propputref setter.据我所知,这就是你想要的.

Zip forward to VB.NET, Microsoft decided that the ambiguity was too painful and eliminated the notion of a default non-indexed property. Which blissfully also retired the Set keyword. This however produces a new problem, there isn't any way anymore to write a [ComVisible] class that can have a property of type Object with a setter that accepts an object reference. The language syntax permits only one setter and the COM interop layer in the CLR is missing the plumbing to synthesize two. Notable is that this is just a warning, you still get the propput setter, you just won't get the propputref setter. Which as far as I can tell is all you want anyway.

在 VB6 虚拟类中定义接口或通过显式编写 IDL 并使用 midl.exe 编译它确实是绕过警告的一种方法.正如 John Rivard 在这个问题.

Defining the interface either in a VB6 dummy class or by writing the IDL explicitly and compiling it with midl.exe is indeed a way to sail around the warning. As shown by John Rivard in this question.

这篇关于在 .NET 中为互操作公开属性作为变体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆