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

Exposing Property as Variant in .NET for Interop(在 .NET 中将属性公开为变体以进行互操作)
本文介绍了在 .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 不能作为属性让"公开给 COM.从 Visual Basic 6.0 开始,您将无法使用Let"语句为该属性分配非对象值(例如数字或字符串).*

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 自动化通过允许一个属性有 两个 设置器来实现这一点.在 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 设置器,只是不会得到 propputref 设置器.据我所知,这就是你想要的.

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 在 this question.

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 中将属性公开为变体以进行互操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)