Pergunta

Eu tenho estado a olhar para Reflection.Emit recentemente. Eu escrevi um programa simples que gera um DynamicMethod que simples chama outro método com os mesmos parâmetros

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

Quando eu executar este exemplo que eu esperaria que a saída 1,2,3,4,5,6 no entanto, saídas 2,3,4,5,6,1

Eu não estou muito certo porque ... Se vocês sabe de qualquer bons recursos para usar Reflection.Emit você poderia me apontar nessa direção. Tenho vindo a utilizar refletor com o Emit AddIn.

Felicidades

Rohan

Foi útil?

Solução

O problema que você tem é que você está invocando um método dinâmico, não um estático. Seu método gerado não tem uma referência para a instância da classe Programa.

Além disso, note que você está empurrando 7 parâmetros para a pilha para um método 6 parâmetro. O primeiro parâmetro deve ser uma referência para o objeto que você está invocando o método on.

O comportamento estranho que você está vendo pode ser devido a não haver um parâmetro de índice 6, e envolvendo em torno de volta para o início da matriz de parâmetro.

Consulte "Como definir e executar Métodos dinâmicos" na ajuda VS

.

Você pode fazê-lo funcionar, aceitando um parâmetro de objeto em sua chamada de método, ou torná-lo estático:

delegado pública TestHandler vazio (instância de objecto, int a, b int, int c, 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);
}

Outras dicas

Para fazer o trabalho você deve

  1. Faça Question um método static
  2. comentário gen.Emit(OpCodes.Ldarg_S,6);
  3. modificar MethodInfo method1 = ... conformidade

Um "cheiro" é que parar na depuração no método Question você não pode avaliar a referência this. E isso não deve ser por um método de instância ...; -)

Edit: Ops. Acabo de ver a resposta de Robert Wagner, que é muito melhor explicou que o meu. Pronto para cancelar meu post se necessário ...: -)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top