我正在尝试使用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并在其上使用了ildasm。以下代码有什么问题吗?
.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文件,没有依赖项)。
答案 0 :(得分:3)
List<T>
实际上有3个GetEnumerator()
方法;它显式实现了IEnumerable.GetEnumerator()
和IEnumerable<T>.GetEnumerator()
,但它还有一个公共GetEnumerator()
方法返回一个List<T>.Enumerator
实例,它是一个值类型。您的代码正在调用该方法,因此您需要在box
和call
之间插入ret
操作码。
为了将来参考,如果您只是编译示例C#代码并在Reflector中查看它并将其与您自己的IL进行比较,这很容易理解。
您的IL的另一个问题是您的显式接口实现不应该是公共的,它应该是私有的。还有一些其他的细微差别,但我认为其中任何一个都不会导致异常。