什么可能导致此 ExecutionEngineException?
我正在尝试使用 Reflection.Emit 在动态程序集中生成包装类。自动包装器生成是我正在编写的名为“GoInterfaces”的新开源库的一部分。
包装类实现 IEnumerable
并包装 List
。用 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
时才会出现此问题。如果有人愿意,我很乐意发送源代码(2 个 *.cs 文件,无依赖项)。
I am trying to use Reflection.Emit to generate a wrapper class in a dynamic assembly. Automatic wrapper generation is part of a new open-source library I'm writing called "GoInterfaces".
The wrapper class implements IEnumerable<string>
and wraps List<string>
. In C# terms, all it does is this:
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();
}
}
However, when I try to call the GetEnumerator() method on my wrapper class, I get ExecutionEngineException. So I saved my dynamic assembly to a DLL and used ildasm on it. Is there anything wrong with the following code?
.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
...
I have a test suite that wraps all sorts of different things, including interfaces derived from other interfaces, and multiple interface methods with identical signatures. It's only when I try to wrap IEnumerable<T>
that this problem occurs. I'd be happy to send the source code (2 *.cs files, no dependencies) if anyone would like.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
List
实际上有 3 个GetEnumerator()
方法;它显式实现IEnumerable.GetEnumerator()
和IEnumerable.GetEnumerator()
,但它还有一个公共GetEnumerator()
方法返回List.Enumerator
实例,它是一个值类型。您的代码正在调用该方法,因此您需要在call
和ret
之间插入一个box
操作码。为了供将来参考,如果您只是编译示例 C# 代码并在 Reflector 中查看它并将其与您自己的 IL 进行比较,就很容易弄清楚这一点。
IL 的另一个问题是显式接口实现不应该是公共的,而应该是私有的。还有一些其他细微差别,但我认为这些差异都不会导致异常。
List<T>
actually has 3GetEnumerator()
methods; it explicitly implementsIEnumerable.GetEnumerator()
andIEnumerable<T>.GetEnumerator()
, but it also has a publicGetEnumerator()
method returning aList<T>.Enumerator
instance, which is a value type. Your code is calling that method, and therefore you need to insert abox
opcode between thecall
and theret
.For future reference, this is pretty easy to figure out if you just compile your example C# code and look at it in Reflector and compare that to your own IL.
Another issue with your IL is that your explicit interface implementation should not be public, it should be private. There are also a few other minor differences, but I don't think that any of these would cause the exception.