2010-06-23 7 views
2

Je passais en revue un article Dodge Common Performance Pitfalls to Craft Speedy Applications de Joel Pobar sur Reflection et je regardais un morceau particulier de code qui ne compile pas (légèrement modifié pour affiner l'erreur spécifique, parce que son exemple avait plus d'erreurs):Générer DynamicMethod à partir de MethodInfo

MethodInfo writeLine = typeof(Console).GetMethod("WriteLine"); 
RuntimeMethodHandle myMethodHandle = writeLine.MethodHandle; 
DynamicMethod dm = new DynamicMethod(
    "HelloWorld",   // name of the method 
    typeof(void),   // return type of the method 
    new Type[]{},   // argument types for the method 
    false);    // skip JIT visibility checks 

ILGenerator il = dm.GetILGenerator(); 
il.Emit(OpCodes.Ldstr, "Hello, world"); 
il.Emit(OpCodes.Call, myMethodHandle); // <-- 2 errors here 
il.Emit(OpCodes.Ret); 

Les erreurs sont les suivantes:

Program.cs(350,13): error CS1502: The best overloaded method match for 'System.Reflection.Emit.ILGenerator.Emit(System.Reflection.Emit.OpCode, byte)' has some invalid arguments 
Program.cs(350,35): error CS1503: Argument '2': cannot convert from 'System.RuntimeMethodHandle' to 'byte' 

Le ILGenerator peut Emit avec un MethodInfo, mais il ne semble pas soutenir MethodHandle ... Quelqu'un savoir comment faire fonctionner cet échantillon?

Répondre

2

Comme ça?

 MethodInfo writeLine = typeof(Console).GetMethod("WriteLine", new Type[] {typeof(string)}); 
     RuntimeMethodHandle myMethodHandle = writeLine.MethodHandle; 
     DynamicMethod dm = new DynamicMethod(
      "HelloWorld",   // name of the method 
      typeof(void),   // return type of the method 
      new Type[] { },   // argument types for the method 
      false);    // skip JIT visibility checks 

     ILGenerator il = dm.GetILGenerator(); 
     il.Emit(OpCodes.Ldstr, "Hello, world"); 
     il.EmitCall(OpCodes.Call, writeLine, null); 
     il.Emit(OpCodes.Ret); 
     // test it 
     Action act = (Action)dm.CreateDelegate(typeof(Action)); 
     act(); 

Changements:

  • J'ai utilisé un pincé GetMethod pour trouver la (string) surcharge (sinon il est une correspondance ambiguë)
  • utiliser le MethodInfo, pas la poignée (puisque c'est ce que ILGenerator veut
  • utiliser EmitCall (l'autre pourrait avoir travaillé aussi, mais je sais de cette façon fonctionne)
0

Grâce à cette bibliothèque Nuget.org: ClassWrapper

Il crée des enveloppes pour les types qui utilisent des méthodes internes générées dynamiquement. Donc, aucune réflexion n'est utilisée (seulement dans la méthode ClassWrapperDescriptor.Load pour générer les expressions dynamiques)

Étant donné, par ex. La classe e nommée SampleClass

//Create the class wrapper descriptor, this can be cached and reused! 
var classWrapperDescriptor = new ClassWrapperDescriptor(typeof(SampleClass)); 
//Initialize the descriptor 
classWrapperDescriptor.Load(); 

//Create the instance of our object 
object instance = new SampleClass(); 

//Create an instance of the wrapper 
var classWrapper = classWrapperDescriptor.CreateWrapper(instance); 

//Set a property 
classWrapper.Set("StringProperty","test"); 

//Get a property 
var stringPropertyValue = classWrapper.Get<string>("StringProperty"); 

//Invoke a method without return statement 
classWrapper.Invoke("ParamMethod", "paramValue"); 

//Invoke a method witho return statement 
var result = classWrapper.Invoke<int>("ReturnMethod", "paramValue"); 

Tous les commentaires sur cette bibliothèque sont vraiment appréciés!

+0

ClassWrapper n'a même pas 'Load()' mon type: 'var classWrapperDescriptor = nouveau ClassWrapperDescriptor (typeof (MyDataContext));' 'classWrapperDescriptor.Load(); // renvoie une exception de référence nulle' –

+0

Bonjour @Don P, pouvez-vous déposer un bug sur https://github.com/kendarorg/ClassWrapper (ou ajouter un commentaire ici) Avec la définition de la classe que vous essayez de charger? Merci pour l'aide! – EDR

Questions connexes