Using Reflection.Emit to match existing constructor
First, here is the C# code and the disassembled IL:
public class Program<T>
{
private List<T> _items;
public Program(T x, [Microsoft.Scripting.ParamDictionary] Microsoft.Scripting.IAttributesCollection col)
{
_items = new List<T>();
_items.Add(x);
}
}
Here is the IL of that constructor:
.method public hidebysig specialname rtspecialname
instance void .ctor(!T x,
class [Microsoft.Scripting]Microsoft.Scripting.IAttributesCollection col) cil managed
{
.param [2]
.custom instance void [Microsoft.Scripting]Microsoft.Scripting.ParamDictionaryAttribute::.ctor() = ( 01 00 00 00 )
// Code size 34 (0x22)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: newobj instance void class [mscorlib]System.Collections.Generic.List`1<!T>::.ctor()
IL_000e: stfld class [mscorlib]System.Collections.Generic.List`1<!0> class Foo.Program`1<!T>::_items
IL_0013: ldarg.0
IL_0014: ldfld class [mscorlib]System.Collections.Generic.List`1<!0> class Foo.Program`1<!T>::_items
IL_0019: ldarg.1
IL_001a: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<!T>::Add(!0)
IL_001f: nop
IL_0020: nop
IL_0021: ret
} // end of method Program`1::.ctor
I am trying to understand the IL code by emitting it myself. This is what I have managed to emit:
.method public hidebysig specialname rtspecialname
instance void .ctor(!T A_1,
class [Microsoft.Scripting]Microsoft.Scripting.IAttributesCollection A_2) cil managed
{
// Code size 34 (0x22)
.maxstack 4
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: newobj instance void class [mscorlib]System.Collections.Generic.List`1<!T>::.ctor()
IL_000c: stfld class [mscorlib]System.Collections.Generic.List`1<!0> class MyType<!T>::_items
IL_0011: ldarg.0
IL_0012: ldfld class [mscorlib]System.Collections.Generic.List`1<!0> class MyType<!T>::_items
IL_0017: ldarg.s A_1
IL_0019: nop
IL_001a: nop
IL_001b: nop
IL_001c: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<!T>::Add(!0)
IL_0021: ret
} // end of method MyType::.ctor
开发者_如何学编程There are a few differences that I just can't figure out. I'm really close...
How do I take care of the parameter attribute (ParamDictionaryAttribute)? I can't find a 'custom' opcode.
Is the .param [2] important? How do I emit that?
Why is the C# code stack size 8, while my emitted version is 4? Is this important?
.custom
is not opcode, it is the way to apply custom attribute. It is part of declaration. It is tightly bound with .param
. .param[2]
tells that now we will speak about 2nd parameter. .custom
applies specified parameter. Take a look at MSIL spec, page 225 and 201 and 199 (for .maxstack)
To set custom attribute on parameter call DefineParameter
on ctor and you get ParameterBuilder
call SetCustomAttribute()
on it
-> 1./2. Use DefineParameter()
on the constructor builder (instead of defining them with the type[]
), and then you can do a SetCustomAttribute()
to apply the attribute to the parameter.
-> 3. That's not important I think. It basically specifies how much stack must be available for the method to be able to run.
精彩评论