使用显式接口实现时,如何选择导出到COM的成员

本文关键字:COM 成员 选择 显式接口实现 何选择 | 更新日期: 2023-09-27 18:17:56

如果我的类实现IEnumerable,我可以使用VBScript的For Each循环:

[ComVisible(true)]
[ProgId("Stackoverflow.MyIssues")]
[Guid("7D392CB1-9080-49D0-B9CE-05B214B2C448")]
public class MyIssue : IEnumerable
{
  readonly List<string> issues = new List<string>(new string[] { "foo", "bar" });
  public string this[int index]
  {
    get { return issues[index]; }
  }
  public IEnumerator GetEnumerator()
  {
    return issues.GetEnumerator();
  }
}

Dim o : Set o = CreateObject("Stackoverflow.MyIssues")
Dim i
For Each i In o
  WScript.Echo i
Next

如果我将接口更改为IEnumerable<string>(因此c#的foreach循环使用string而不是object):

public class MyIssue : IEnumerable<string>

并将GetEnumerator替换为:

public IEnumerator<string> GetEnumerator()
{
  return issues.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
  return GetEnumerator();
}

脚本将失败并出现错误:

对象不支持此属性或方法

我的理解是,公共GetEnumerator()不被导出,因为它是一个通用方法,IEnumerable.GetEnumerator不导出,因为我的实例必须首先转换为IEnumerable,但在VBScript不能把对象。

这是真的吗?是否有可能告诉编译器IEnumerable.GetEnumerator应该是导出为public IEnumerable GetEnumerator ?(或者这句话是否定的理解吗?等)

使用显式接口实现时,如何选择导出到COM的成员

切换显式实现的接口,例如:

IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
    // ...
}
public IEnumerator GetEnumerator()
{
    // ...
}

这是因为IEnumerable.GetEnumerator具有DispId(-4)属性,这是VBScript通过IDispatch.Invoke使用的。

泛型方法和泛型方法在COM中是不可见的,所以如果你不想改变你的代码,为COM定义一个额外的方法:

// Test if the .NET framework dispatches the method if you apply the following attribute
//[ComVisible(false)]
[DispId(-4)]
public IEnumerator NewEnum()
{
    return ((IEnumerable)this).GetEnumerator();
}