使用 Reflection.Emit 匹配现有构造函数

发布于 2024-08-27 11:25:43 字数 2664 浏览 2 评论 0原文

首先,这是 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

有一些我无法弄清楚的差异。我真的很接近...

  1. 我如何处理参数属性(ParamDictionaryAttribute)?我找不到“自定义”操作码。

  2. .param [2] 重要吗?我如何发出它?

  3. 为什么 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...

  1. How do I take care of the parameter attribute (ParamDictionaryAttribute)? I can't find a 'custom' opcode.

  2. Is the .param [2] important? How do I emit that?

  3. Why is the C# code stack size 8, while my emitted version is 4? Is this important?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

酒几许 2024-09-03 11:25:43

.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 get ParameterBuilder call SetCustomAttribute() on it

无人接听 2024-09-03 11:25:43

-> 1./2.使用 DefineParameter() 在构造函数生成器上(而不是使用 type[] 定义它们),然后您可以执行 SetCustomAttribute() 将属性应用于参数。

-> 3.我认为这并不重要。它基本上指定了该方法必须有多少可用堆栈才能运行。

-> 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文