2010-03-30 5 views
4

Tout d'abord, voici le code C# et démontées IL:En utilisant Reflection.Emit pour correspondre constructeur existant

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

Voici l'IL de ce constructeur:

.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 

Je suis en train de comprendre le code IL en l'émettant moi-même. C'est ce que j'ai réussi à émettre:

.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 

Il y a quelques différences que je n'arrive pas à comprendre. Je suis vraiment fermer ...

  1. Comment puis-je prendre soin de l'attribut de paramètre (ParamDictionaryAttribute)? Je ne peux pas trouver un opcode 'custom'.

  2. Le paramètre .param [2] est-il important? Comment puis-je l'émettre?

  3. Pourquoi la pile de codes C# est-elle de taille 8 alors que ma version émise est 4? Est-ce important?

Répondre

3

.custom n'est pas l'opcode, c'est la façon d'appliquer un attribut personnalisé. Cela fait partie de la déclaration. Il est étroitement lié avec .param. .param[2] dit que maintenant nous allons parler de 2ème paramètre. .custom applique le paramètre spécifié. Jetez un oeil à MSIL spec, page 225, 201 et 199 (pour .maxstack)

Pour définir attribut personnalisé sur le paramètre appel DefineParameter sur cteur et vous obtenez ParameterBuilder appel SetCustomAttribute() sur elle

1

-> 1./2. Utilisez DefineParameter() sur le constructeur constructeur (au lieu de les définir avec le type[]), puis vous pouvez faire un SetCustomAttribute() pour appliquer l'attribut au paramètre.

-> 3. Ce n'est pas important je pense. Il spécifie essentiellement combien de pile doit être disponible pour que la méthode puisse fonctionner.

+0

utilisant SetCustomAttribute() sur cteur appliquera attrib à ctor, mais il est appliqué au paramètre, voir ma réponse. – Andrey

+0

Désolé, je ne m'en suis pas rendu compte. Mise à jour ma réponse (et +1 pour vous). – Lucero

Questions connexes