泛型和 Com Visible .NET 库

Posted

技术标签:

【中文标题】泛型和 Com Visible .NET 库【英文标题】:Generics and Com Visible .NET libraries 【发布时间】:2015-06-16 06:59:53 【问题描述】:

我开发了一个 VB.NET 库(部分也是基于 C# 开发的),它严重依赖于从抽象泛型基类继承,我正在尝试找出最佳实践。我很遗憾必须使用框架 3.5 来完成。

Public MustInherit Class MyBaseClass(Of T)
  Public Whatever As T
End Class

Public Class MyDerivedClass
  Inherits MyBaseClass(Of String)

  Private _myProperty As String

  Public Property MyProperty As String
    Get
      Return _myProperty
    End Get
    Set(value As String)
      _myProperty = value
    End Set
  End Property
End Class

我附加 .tlb 文件作为 VBA 中的参考(使用 Excel),然后运行以下代码:

Dim m As New VBtoVBA.MyDerivedClass
m.MyProperty = "foo"

我收到错误“运行时错误 430:类不支持自动化或不支持预期的接口”。

另一方面,我将第一行更改为:

Public MustInherit Class MyBaseClass
  Public Whatever As String
End Class

Public Class MyDerivedClass
  Inherits MyBaseClass

VBA 脚本有效。因此,我认为问题出在泛型上(正如其他来源中所记录的那样)。但是,删除我的库的通用特性是不可能的。我能想到的“最佳”解决方法是编写第三个类,其中包含 MyDerivedClass 作为一个字段,并作为它的非泛型接口工作:

Public Class MyDerivedClassString

  Private _innerObj As New MyDerivedClass

  Public Property MyProperty As String
    Get
      Return _innerObj.MyProperty
    End Get
    Set(value As String)
      _innerObj.MyProperty = value
    End Set
  End Property

  Public Property Whatever As String
    Get
      Return _innerObj.Whatever
    End Get
    Set(value As String)
      _innerObj.Whatever = value
    End Set
  End Property

End Class

这样我就可以像在 VBA 中那样使用它:

m.Whatever = "wha"
MsgBox (m.Whatever)

顺便说一句,我认为可能有另一种(更好的)方法来实现相同的结果,我真的希望如此,因为 m 库由几十个类组成。

非常感谢。

【问题讨论】:

如果我是你,我会在 VBNet 项目中明确定义一个 COM 接口,让MyDerivedClass 实现它(另外,给接口一个 GUID,给MyDerivedClass 另一个 GUID),然后看看如果有帮助的话。 COM 和 VBA 都没有泛型的概念。您的课程根本不会被导出。因此错误。 @Dave 解决方法是不公开泛型。 @Med - 没错,但 COM 也不支持实现继承。它需要创建与类定义匹配的接口类型,基类的接口将是通用的。显式声明接口总是更好,这样类的实际实现就无关紧要了。 根据我的经验,为 MS Office 应用程序编写 COM 库有点……硬编码。请注意,一个接口可以由几个类实现。 【参考方案1】:

正如我在 MS Office 应用程序的评论编写库 (dll) 中提到的那样,有点……硬编码。此 dll 必须公开方法和属性才能在 COM 自动化中使用它。为了能够实现这一点,您需要编写接口:

Namespace VBtoVBA
    Public Interface IMyDerivedClass
        Property MyProperty As String
    End Interface
End Namespace

然后在 DerivedClass 中

Public Class MyDerivedClass
    Inherits MyBaseClass(Of String)
    Implements IMyDerivedClass

    Private _myProperty As String

    Public Property MyProperty As String Implements IMyDerivedClass.MyProperty

现在,转到Project Properties 窗口 1) 选择Application 选项卡 - 点击Assembly Information 按钮并在下一个窗口中选择Make assembly COM visible 复选框(使用OK 按钮应用设置),

2) 选择 Compile 选项卡 - 选择 Register for COM interop 复选框

3) 保存项目并构建 dll

4) 现在,转到 Office 应用程序中的 VBA 代码编辑器 -> References 菜单。在Reference window 中添加对yourDllName.tlb 的引用

现在,您可以在 Office 应用程序中使用您的 dll 了;)

我测试过代码:

Option Explicit

Sub DoSomething()
Dim m As VBtoVBA.MyDerivedClass

Set m = New VBtoVBA.MyDerivedClass

m.MyProperty = "Something"

MsgBox m.MyProperty


End Sub

它也有效;)

【讨论】:

以上是关于泛型和 Com Visible .NET 库的主要内容,如果未能解决你的问题,请参考以下文章

C#/.NET 泛型和 Cdecl Varargs 错误?

具有多个结构的泛型和依赖倒置

泛型和链表

GenericDAO 与 Guice,玩泛型和 ParameterizedType

为什么要使用泛型?泛型和非泛型对比

Java 泛型和可变参数