4 Stimmen

Reflection.Emit verwenden, um den vorhandenen Konstruktor anzupassen

Hier ist zunächst der C#-Code und die disassemblierte AWL:

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);
    }
}

Hier ist die AWL dieses Konstruktors:

.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

Ich versuche, den IL-Code zu verstehen, indem ich ihn selbst emittiere. Dies ist, was ich geschafft habe, zu emittieren:

.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

Es gibt ein paar Unterschiede, die ich einfach nicht verstehen kann. Ich bin wirklich nah dran...

  1. Wie kümmere ich mich um das Parameterattribut (ParamDictionaryAttribute)? Ich kann keinen "benutzerdefinierten" Opcode finden.

  2. Ist das .param [2] wichtig? Wie kann ich das ausgeben?

  3. Warum ist die C#-Code-Stack-Größe 8, während meine emittierte Version 4 ist? Ist das wichtig?

3voto

Andrey Punkte 57704

.custom ist kein Opcode, sondern die Möglichkeit, benutzerdefinierte Attribute anzuwenden. Es ist Teil der Deklaration. Es ist eng verbunden mit .param . .param[2] sagt, dass wir jetzt über den 2. Parameter sprechen werden. .custom wendet den angegebenen Parameter an. Schauen Sie sich MSIL-Spezifikation , Seite 225 und 201 und 199 (für .maxstack)

So setzen Sie ein benutzerdefiniertes Attribut beim Parameteraufruf DefineParameter auf ctor und Sie erhalten ParameterBuilder aufrufen SetCustomAttribute() darauf

1voto

Lucero Punkte 57715

-> 1./2. verwenden DefineParameter() beim Konstruktorersteller (anstatt sie mit der Option type[] ), und dann können Sie eine SetCustomAttribute() um das Attribut auf den Parameter anzuwenden.

-> 3. Ich denke, das ist nicht wichtig. Es gibt im Grunde an, wie viel Stack verfügbar sein muss, damit die Methode ausgeführt werden kann.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X