Использование 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

Есть несколько отличий, которые я просто не могу понять. я очень близко...

  1. Как мне позаботиться об атрибуте параметра (ParamDictionaryAttribute)? Я не могу найти «пользовательский» код операции.

  2. Важен ли параметр .param [2]? Как мне это излучать?

  3. Почему стек кода C# имеет размер 8, а моя выпущенная версия — 4? Это важно?


person Community    schedule 30.03.2010    source источник


Ответы (2)


.custom — это не код операции, это способ применения пользовательского атрибута. Это часть декларации. Он тесно связан с .param. .param[2] говорит о том, что сейчас мы будем говорить о 2-м параметре. .custom применяет указанный параметр. Взгляните на спецификацию MSIL, стр. 225 и 201 и 199 (для .maxstack)

Чтобы установить пользовательский атрибут для параметра, вызовите DefineParameter на ctor, и вы получите ParameterBuilder вызов SetCustomAttribute() на нем.

person Andrey    schedule 30.03.2010

-> 1./2. Используйте DefineParameter()< /a> в построителе конструктора (вместо определения их с помощью type[]), а затем вы можете выполнить SetCustomAttribute(), чтобы применить атрибут к параметру.

-> 3. Думаю, это не важно. В основном он указывает, сколько стека должно быть доступно для запуска метода.

person Lucero    schedule 30.03.2010
comment
использование SetCustomAttribute() для ctor применит атрибут к ctor, но он применяется к параметру, см. мой ответ. - person Andrey; 30.03.2010
comment
Извините, не понял этого. Обновил мой ответ (и +1 для вас). - person Lucero; 30.03.2010