【发布时间】:2021-10-08 18:25:30
【问题描述】:
我注意到,如果我创建一个公开 ArrayList 的 .NET 组件,那么该 ArrayList 会通过 COM Interop 并且可以在脚本语言(例如 VBScript)中使用。
泛型,例如 IList<T> 似乎不起作用。
为什么会这样?有什么方法可以使泛型类型成功地通过 COM 互操作流到脚本引擎?
【问题讨论】:
标签: generics scripting com-interop
我注意到,如果我创建一个公开 ArrayList 的 .NET 组件,那么该 ArrayList 会通过 COM Interop 并且可以在脚本语言(例如 VBScript)中使用。
泛型,例如 IList<T> 似乎不起作用。
为什么会这样?有什么方法可以使泛型类型成功地通过 COM 互操作流到脚本引擎?
【问题讨论】:
标签: generics scripting com-interop
.NET 2.0 中添加了泛型,COM 存在于 .NET 1.0 之前。
(并且是 .NET旨在取代的技术。)
COM 从来没有泛型,因此您不能公开它们。
两种 COM 语言(C++、VB6、Delphi)都没有泛型,因此您不能指望它们会被使用。
(嗯,C++ 有模板,但它们是完全不同的野兽,而 COM 只意味着 接口。)
将集合公开为ArrayList 是solution 解决此问题,您无法解决它。
免责声明:我不是 COM 专家,所以其余答案大致基于我的猜测。
COM 从来没有“拥有”ArrayLists,没错,但是它从来没有任何 .NET Framework 中的类,因为它本身不是一个框架。但是,有些 .NET 类型会进入导出的类型库,而有些则不会。 .NET Framework 类呢?好吧,ArrayList 是 [ComVisible],而 List<T> 不是。
为什么?
COM works via interfaces,而接口定义语言对泛型一无所知,也不支持它们。支持 COM 的语言(例如 VB6 或 C++)不知道如何处理泛型。
如果有办法为List<T> 生成一个接口,它不会在其中包含T,因此尝试公开泛型类型基本上没有意义。可能的想象替代方案是:
IListOfString 为List<string>
T 替换为 object。第一个选项不可行,因为具体的T 类型在编译时可能不知道(阅读:反射),而且List<T> 无论如何都没有[ComVisible] 属性。
第二个选项实际上是可能的,因为你可以provide your own class interface with IList and ICollection properties:
[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)]。你可能想检查一下。
【讨论】: