为什么 ArrayList 可以与 COM 互操作,但 IList<T> 却不能?

7
我注意到如果我创建一个.NET组件,公开一个ArrayList,那么这个ArrayList通过COM互操作传递,并且可以在脚本语言中使用,如VBScript。
泛型,比如IList似乎不起作用。
为什么会这样,有没有办法使一个泛型类型成功地通过COM互操作流动到脚本引擎?

2
因为COM不支持泛型。请看这里这里的问题。 - Dan Abramov
1个回答

10

泛型是在.NET 2.0中添加的,而COM存在于.NET 1.0之前。
(并且.NET旨在取代的技术是COM。)

COM从未具有泛型,因此您无法公开它们。
COM语言(C ++、VB6、Delphi)都没有泛型,因此不能指望它们被使用。
(好吧,C ++有模板,但它们完全是不同的东西,而COM只意味着接口。)

将集合公开为ArrayList是解决此问题的解决方案,您无法绕过它。

免责声明:我不是COM专家,因此答案的其余部分基本上是根据我的猜测。

COM从未“拥有”ArrayList,这是真的,但是它从未拥有.NET Framework中的任何类,因为它本身不是一个框架。但是,一些.NET类型进入了导出的类型库,而有些则没有。那么.NET Framework类呢?好吧,ArrayList[ComVisible]的,而List<T>则不是。

为什么?

COM通过接口工作,而接口定义语言不知道泛型并且不支持它们。支持COM的语言(例如VB6或C ++)不知道如何处理泛型。

如果有一种方法可以为List<T>生成接口,则不会在其中包含T,因此尝试公开通用类型实际上没有任何意义。可能的虚构替代方案包括:

  • 为通用类型生成“特定”版本的接口,例如IListOfString用于List<string>
  • 擦除泛型类型信息(就像Java在编译时所做的那样),并将T替换为object

第一个选项不可行,因为具体的T类型可能在编译时未知(读取:反射),而List<T>也没有[ComVisible]属性。

第二个选项实际上是可能的,因为您可以使用IListICollection属性提供自己的类接口:

[ComVisible(true)]
public interface IPerson
{
    string Name { get;set;}
    DateTime Entered { get;set;}
    IList NickNamesList { get;}
    ICollection NickNamesCollection { get;}
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComDefaultInterface(typeof(IPerson))]
public class Person:IPerson
{
    [ComVisible(false)]
    public List<string> NickNames
    {
        get { return _NickNames; }
        set { _NickNames = value; }
    }
    private List<string> _NickNames = new List<string>();

    #region IPerson Members
    IList IPerson.NickNamesList
    {
        get { return this.NickNames; }
    }

    ICollection IPerson.NickNamesCollection
    {
        get { return this.NickNames; }
    }
    #endregion
    ....
}

这只是一个解决方法,并没有回答你的问题。
我想知道是否可以从 List<string> 派生出你的 StringList 类,并将其标记为 [ComVisible(true)]。你可能需要检查一下。

1
我无法接受这一点。微软让ArrayList工作了(COM从未拥有过ArrayList),所以肯定有办法让其他类型也能工作。泛型在运行时具有具体类型。是什么机制使ArrayList起作用? - Tim Long
我不是COM方面的专家,但我编辑了答案并加入了一些猜测。 - Dan Abramov
假设使用迟绑定(IDispatch),看看是否对事情产生不同的影响。在运行时,每个.NET类型都是具体类型,因此只要从COM组件中使用迟绑定,它就应该能够“看到”从泛型派生的具体类型。鉴于COM有自己的类型系统,在.NET类型和COM类型之间需要进行一些转换。我今天已经阅读了一些资料,现在我想知道是否可能使用自定义编组程序将通用类型“公开”给COM?尽管我的COM知识非常薄弱,但我只是在瞎猜。 - Tim Long

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接