Question

J'ai consulté Reflection.Emit récemment. J'ai écrit un programme simple qui génère un DynamicMethod qui appelle simplement une autre méthode avec les mêmes paramètres

class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();
        p.Test();
    }

    public delegate void TestHandler(int a, int b, int c, int d, int e, int f);

    public void Test()
    {
        DynamicMethod method = new DynamicMethod(string.Empty, typeof(void), new[] { typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, typeof(Program));


        MethodInfo method1 = typeof(Program).GetMethod("Question",BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,null,new Type[]{typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32)},null);
        MethodInfo method2 = typeof(MethodBase).GetMethod("GetCurrentMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null);
        MethodInfo method3 = typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Object) }, null);

        ILGenerator gen = method.GetILGenerator();

        gen.Emit(OpCodes.Nop);
        gen.Emit(OpCodes.Ldarg_S, 0);
        gen.Emit(OpCodes.Ldarg_S, 1);
        gen.Emit(OpCodes.Ldarg_S, 2);
        gen.Emit(OpCodes.Ldarg_S, 3);
        gen.Emit(OpCodes.Ldarg_S, 4);
        gen.Emit(OpCodes.Ldarg_S, 5);
        gen.Emit(OpCodes.Ldarg_S, 6);
        gen.Emit(OpCodes.Call, method1);
        gen.Emit(OpCodes.Nop);
        gen.Emit(OpCodes.Call, method2);
        gen.Emit(OpCodes.Call, method3);
        gen.Emit(OpCodes.Nop);
        gen.Emit(OpCodes.Ret);

        TestHandler handler = method.CreateDelegate(typeof(TestHandler)) as TestHandler;
        handler(1, 2, 3, 4, 5, 6);
    }

    public void Question(int a, int b, int c, int d, int e, int f)
    {
        Console.WriteLine("{0},{1},{2},{3},{4},{5}", a, b, c, d, e, f);
    }
}

Quand j’exécute cet exemple, il s’attendrait à produire 1,2,3,4,5,6 mais il produit 2,3,4,5,6,1

Je ne sais pas trop pourquoi ... Si vous connaissez des ressources utiles pour utiliser Reflection.Emit, pourriez-vous me diriger dans cette direction. J'utilise Reflector avec Emit AddIn.

A bientôt

Rohan

Était-ce utile?

La solution

Le problème que vous rencontrez est que vous appelez une méthode dynamique, pas statique. Votre méthode générée ne fait pas référence à l'instance de la classe Program.

Notez également que vous mettez 7 paramètres sur la pile pour une méthode à 6 paramètres. Le premier paramètre doit être une référence à l'objet sur lequel vous appelez la méthode.

Le comportement étrange que vous observez est peut-être dû au fait qu'il n'y a pas de paramètre d'indice 6 et qu'il retourne au début du tableau de paramètres.

Voir "Comment: définir et exécuter des méthodes dynamiques" dans l'aide VS.

Vous pouvez le faire fonctionner en acceptant un paramètre d'objet dans votre appel de méthode ou en le rendant statique:

Délégué public void TestHandler (instance d'objet, int b, int b, int c, int d, int e, int f);

public void Test()
{
    DynamicMethod method = new DynamicMethod(string.Empty, typeof(void), new[] { typeof(object), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, typeof(Program));


    MethodInfo method1 = typeof(Program).GetMethod("Question", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, null);
    MethodInfo method2 = typeof(MethodBase).GetMethod("GetCurrentMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null);
    MethodInfo method3 = typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Object) }, null);

    ILGenerator gen = method.GetILGenerator();

    gen.Emit(OpCodes.Nop);
    gen.Emit(OpCodes.Ldarg_S, 0);
    gen.Emit(OpCodes.Ldarg_S, 1);
    gen.Emit(OpCodes.Ldarg_S, 2);
    gen.Emit(OpCodes.Ldarg_S, 3);
    gen.Emit(OpCodes.Ldarg_S, 4);
    gen.Emit(OpCodes.Ldarg_S, 5);
    gen.Emit(OpCodes.Ldarg_S, 6);
    gen.Emit(OpCodes.Call, method1);
    gen.Emit(OpCodes.Nop);
    gen.Emit(OpCodes.Call, method2);
    gen.Emit(OpCodes.Call, method3);
    gen.Emit(OpCodes.Nop);
    gen.Emit(OpCodes.Ret);

    TestHandler handler = method.CreateDelegate(typeof(TestHandler)) as TestHandler;
    handler(this, 1, 2, 3, 4, 5, 6);
}

public void Question(int a, int b, int c, int d, int e, int f)
{
    Console.WriteLine("{0},{1},{2},{3},{4},{5}", a, b, c, d, e, f);
}

Autres conseils

Pour que cela fonctionne, vous devriez

  1. créer Question une méthode statique
  2. comment gen.Emit (OpCodes.Ldarg_S, 6);
  3. modifier MethodInfo method1 = ... en conséquence

Une "odeur" Si vous arrêtez le processus de débogage avec la méthode Question , vous ne pouvez pas évaluer le code this . Et cela ne devrait pas être pour une méthode d'instance ...; -)

Edit: Ops. Je viens de voir la réponse de Robert Wagner qui est beaucoup mieux expliquée que la mienne. Prêt à annuler mon message si nécessaire ...: -)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top