Reputation: 17186
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.
Upvotes: 1
Views: 534
Reputation: 55184
List<T>
actually has 3 GetEnumerator()
methods; it explicitly implements IEnumerable.GetEnumerator()
and IEnumerable<T>.GetEnumerator()
, but it also has a public GetEnumerator()
method returning a List<T>.Enumerator
instance, which is a value type. Your code is calling that method, and therefore you need to insert a box
opcode between the call
and the ret
.
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.
Upvotes: 3