Использование Reflection.Emit для соответствия существующему конструктору - PullRequest
4 голосов
/ 30 марта 2010

Во-первых, вот код 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? Это важно?

Ответы [ 2 ]

3 голосов
/ 30 марта 2010

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

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

1 голос
/ 30 марта 2010

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

-> 3. Это не важно, я думаю. Это в основном указывает, сколько стека должно быть доступно для того, чтобы метод мог работать.

...