我注意到如果我创建一个.NET组件,公开一个ArrayList,那么这个ArrayList通过COM互操作传递,并且可以在脚本语言中使用,如VBScript。
泛型,比如IList似乎不起作用。
为什么会这样,有没有办法使一个泛型类型成功地通过COM互操作流动到脚本引擎?
泛型,比如IList似乎不起作用。
为什么会这样,有没有办法使一个泛型类型成功地通过COM互操作流动到脚本引擎?
泛型是在.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>
T
替换为object
。第一个选项不可行,因为具体的T
类型可能在编译时未知(读取:反射),而List<T>
也没有[ComVisible]
属性。
第二个选项实际上是可能的,因为您可以使用IList
和ICollection
属性提供自己的类接口:
[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)]
。你可能需要检查一下。