1

我正在尝试使用 Reflection.Emit 在动态程序集中生成包装类。自动包装器生成是我正在编写的名为“GoInterfaces”的新开源库的一部分。

包装类实现IEnumerable<string>并包装List<string>. 在 C# 术语中,它所做的只是:

class List1_7931B0B4_79328AA0 : IEnumerable<string>
{
    private readonly List<string> _obj;

    public List1_7931B0B4_79328AA0(List<string> obj)
    {
        this._obj = obj;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this._obj.GetEnumerator();
    }
    public sealed IEnumerator<string> GetEnumerator()
    {
        return this._obj.GetEnumerator();
    }
}

但是,当我尝试在包装类上调用 GetEnumerator() 方法时,我得到了 ExecutionEngineException。所以我将我的动态程序集保存到一个 DLL 并在其上使用了 il​​dasm。下面的代码有什么问题吗?

.class public auto ansi sealed List`1_7931B0B4_79328AA0
    extends [mscorlib]System.Object
    implements [mscorlib]System.Collections.Generic.IEnumerable`1<string>, 
               [Loyc.Runtime]Loyc.Runtime.IGoInterfaceWrapper
{
    .field private initonly class 
        [mscorlib]System.Collections.Generic.List`1<string> _obj

    .method public hidebysig virtual final instance 
            class [mscorlib]System.Collections.Generic.IEnumerator`1<string> 
            GetEnumerator() cil managed
    {
        // Code size       12 (0xc)
        .maxstack  1
        IL_0000:  ldarg.0
        IL_0001:  ldfld      class [mscorlib]System.Collections.Generic.List`1<string> List`1_7931B0B4_79328AA0::_obj
        IL_0006:  call       instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
        IL_000b:  ret
    } // end of method List`1_7931B0B4_79328AA0::GetEnumerator


    .method public hidebysig virtual final instance 
            class [mscorlib]System.Collections.IEnumerator 
            System.Collections.IEnumerable.GetEnumerator() cil managed
    {
        .override [mscorlib]System.Collections.IEnumerable::GetEnumerator
        // Code size       12 (0xc)
        .maxstack  1
        IL_0000:  ldarg.0
        IL_0001:  ldfld      class [mscorlib]System.Collections.Generic.List`1<string> List`1_7931B0B4_79328AA0::_obj
        IL_0006:  call       instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
        IL_000b:  ret
    } // end of method List`1_7931B0B4_79328AA0::System.Collections.IEnumerable.GetEnumerator
    ...

我有一个测试套件,它包含各种不同的东西,包括从其他接口派生的接口,以及具有相同签名的多个接口方法。只有当我尝试包装IEnumerable<T>时才会出现此问题。如果有人愿意,我很乐意发送源代码(2 个 *.cs 文件,无依赖项)。

4

1 回答 1

3

List<T>实际上有3个GetEnumerator()方法;它显式地实现了IEnumerable.GetEnumerator()and IEnumerable<T>.GetEnumerator(),但它也有一个返回实例的公共GetEnumerator()方法,它是一个值类型。List<T>.Enumerator您的代码正在调用该方法,因此您需要在和box之间插入一个操作码。callret

为了将来参考,如果您只是编译您的示例 C# 代码并在 Reflector 中查看它并将其与您自己的 IL 进行比较,这很容易弄清楚。

你的 IL 的另一个问题是你的显式接口实现不应该是公共的,它应该是私有的。还有一些其他的细微差别,但我认为这些都不会导致异常。

于 2010-06-15T14:21:30.880 回答