使用 Reflection.Emit 匹配现有构造函数
首先,这是 C# 代码和反汇编的 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);
}
}
这是该构造函数的 IL:
.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
我试图通过自己发出 IL 代码来理解它。这就是我设法发出的:
.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
有一些我无法弄清楚的差异。我真的很接近...
我如何处理参数属性(ParamDictionaryAttribute)?我找不到“自定义”操作码。
.param [2] 重要吗?我如何发出它?
为什么 C# 代码堆栈大小是 8,而我发出的版本是 4?这重要吗?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
.custom
不是操作码,它是应用自定义属性的方式。它是声明的一部分。它与.param
紧密绑定。.param[2]
告诉我们现在我们将讨论第二个参数。.custom
应用指定的参数。查看 MSIL 规范,页面225 和 201 和 199(对于 .maxstack)要在参数上设置自定义属性,请在 ctor 上调用
DefineParameter
,并且您会得到ParameterBuilder
调用SetCustomAttribute()
它.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 getParameterBuilder
callSetCustomAttribute()
on it-> 1./2.使用
DefineParameter()
在构造函数生成器上(而不是使用type[]
定义它们),然后您可以执行SetCustomAttribute()
将属性应用于参数。-> 3.我认为这并不重要。它基本上指定了该方法必须有多少可用堆栈才能运行。
-> 1./2. Use
DefineParameter()
on the constructor builder (instead of defining them with thetype[]
), and then you can do aSetCustomAttribute()
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.