Como: Conectar um delegado usando reflexão para cima

Quando você usar reflexão para carregar e executar módulos (assemblies), você não pode usar recursos de linguagem como o translation from VPE for Csharp += operador ou o Visual Basic demonstrativo AddHandler para ligar a eventos.Os procedimentos a seguir mostram como conectar um método existente a um evento obtendo todos os tipos necessários por meio de reflexão e como criar um método dinâmico usando a reflexão emitir e associá-lo para um evento.

Observação:

Para outra maneira de conectar um delegado manipulador de eventos, consulte o exemplo de código para o AddEventHandler método para o EventInfo classe.

Para conectar um delegado usando a reflexão

  1. Carregar um assembly que contém um tipo que gera eventos.Assemblies são normalmente carregados com o Assembly.Load método. Para manter esse exemplo simples, um formulário derivado do assembly corrente é usado, isso o GetExecutingAssembly método é usado para carregar o assembly corrente.

    Dim assem As [Assembly] = [Assembly].GetExecutingAssembly()
    
    Assembly assem = Assembly.GetExecutingAssembly();
    
  2. Obtenha um Type objeto que representa o tipo e criar uma instância do tipo. The CreateInstance(Type) método é usado no código a seguir porque o formulário tem um construtor padrão. Há várias outras sobrecargas do CreateInstance método que você pode usar se o tipo que você está criando não tem um construtor padrão. A nova instância é armazenada sistema autônomo tipo Object para manter a ficção que nada é conhecido sobre o assembly. (Reflexão permite obter os tipos em um assembly sem saber antecipadamente seus nomes.)

    Dim tExForm As Type = assem.GetType("ExampleForm")
    Dim exFormAsObj As Object = _
        Activator.CreateInstance(tExForm)
    
    Type tExForm = assem.GetType("ExampleForm");
    Object exFormAsObj = Activator.CreateInstance(tExForm);
    
  3. Obtenha um EventInfo objeto que representa o evento e use o EventHandlerType propriedade para obter o tipo de delegado usado para manipular o evento. O código a seguir, um EventInfo para o Click evento é obtido.

    Dim evClick As EventInfo = tExForm.GetEvent("Click")
    Dim tDelegate As Type = evClick.EventHandlerType
    
    EventInfo evClick = tExForm.GetEvent("Click");
    Type tDelegate = evClick.EventHandlerType;
    
  4. Obtenha um MethodInfo objeto que representa o método que manipula o evento. O código de programa completos no Exemplo seção mais adiante neste tópico contém um método que corresponde à assinatura do EventHandler delegado, quais identificadores de Click evento, mas você também pode gerar métodos dinâmicos em time de execução. Para obter detalhes, consulte o procedimento que o acompanha Para gerar um manipulador de eventos em time de execução por meio de um método dinâmico.

    Dim miHandler As MethodInfo = _
        GetType(Example).GetMethod("LuckyHandler", _
            BindingFlags.NonPublic Or BindingFlags.Instance)
    
    MethodInfo miHandler = 
        typeof(Example).GetMethod("LuckyHandler", 
            BindingFlags.NonPublic | BindingFlags.Instance);
    
  5. Criar uma instância do delegado, usando o CreateDelegate método. Esse método é estático (Shared no Visual Basic), assim, o tipo de delegado deve ser fornecido. Usar os métodos sobrecarregados de CreateDelegate que têm um MethodInfo é recomendável.

    Dim d As [Delegate] = _
        [Delegate].CreateDelegate(tDelegate, Me, miHandler)
    
    Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
    
  6. Obtenha o add método do acessador e invocá-lo para ligar o evento. Todos os eventos possuem um add acessador e um remove acessador, que estão oculto pela sintaxe das linguagens de alto nível. Por exemplo, translation from VPE for Csharp usa o += operador para ligar a eventos e o Visual Basic usa o demonstrativo AddHandler.O código a seguir obtém o add assessor da Click evento e invoca-ligação tardia, passando na instância do delegado. sistema autônomo argumentos devem ser passados sistema autônomo uma matriz.

    Dim miAddHandler As MethodInfo = evClick.GetAddMethod()
    Dim addHandlerArgs() As Object = { d }
    miAddHandler.Invoke(exFormAsObj, addHandlerArgs)
    
    MethodInfo addHandler = evClick.GetAddMethod();
    Object[] addHandlerArgs = { d };
    addHandler.Invoke(exFormAsObj, addHandlerArgs);
    
  7. Teste o evento.O código a seguir mostra o formulário definidos no exemplo de código.Clicando em formulário chama o manipulador de eventos.

    Application.Run(CType(exFormAsObj, Form))
    
    Application.Run((Form) exFormAsObj);
    

Para gerar um evento manipulador em time de execução usando um método dinâmico

  1. evento-métodos de manipulador podem ser gerados em time de execução, usando métodos dinâmicos leves e emissão de reflexão.Para criar um manipulador de eventos, é necessário o tipo de retorno e os tipos de parâmetro do delegado.Eles podem ser obtidos pelo exame Invoke método. O código a seguir usa o GetDelegateReturnType e GetDelegateParameterTypes métodos para obter essas informações. O código para esses métodos pode ser encontrado no Exemplo seção mais adiante neste tópico.

    Não é necessário nomear um DynamicMethod, para que possa ser usada uma seqüência de caracteres vazia. No código a seguir, o último argumento associa método dinâmico com o tipo corrente, oferecendo o delegado acesso a todos os públicos e os membros privados do Example classe.

    Dim returnType As Type = GetDelegateReturnType(tDelegate)
    If returnType IsNot GetType(Void) Then
        Throw New ApplicationException("Delegate has a return type.")
    End If
    
    Dim handler As New DynamicMethod( _
        "", _
        Nothing, _
        GetDelegateParameterTypes(tDelegate), _
        GetType(Example) _
    )
    
    Type returnType = GetDelegateReturnType(tDelegate);
    if (returnType != typeof(void))
        throw new ApplicationException("Delegate has a return type.");
    
    DynamicMethod handler = 
        new DynamicMethod("", 
                          null,
                          GetDelegateParameterTypes(tDelegate),
                          typeof(Example));
    
  2. gerar um corpo de método.Esse método carrega uma seqüência de caracteres, chama a sobrecarga do MessageBox.Show método que usa uma seqüência de caracteres, exibe o valor retornado na pilha (porque o manipulador não tem nenhum tipo de retorno) e retorna. Para saber mais sobre emitindo métodos dinâmicos, consulte Como: Definir e executar métodos dinâmicos.

    Dim ilgen As ILGenerator = handler.GetILGenerator()
    
    Dim showParameters As Type() = { GetType(String) }
    Dim simpleShow As MethodInfo = _
        GetType(MessageBox).GetMethod("Show", showParameters)
    
    ilgen.Emit(OpCodes.Ldstr, _
        "This event handler was constructed at run time.")
    ilgen.Emit(OpCodes.Call, simpleShow)
    ilgen.Emit(OpCodes.Pop)
    ilgen.Emit(OpCodes.Ret)
    
    ILGenerator ilgen = handler.GetILGenerator();
    
    Type[] showParameters = { typeof(String) };
    MethodInfo simpleShow = 
        typeof(MessageBox).GetMethod("Show", showParameters);
    
    ilgen.Emit(OpCodes.Ldstr, 
        "This event handler was constructed at run time.");
    ilgen.Emit(OpCodes.Call, simpleShow);
    ilgen.Emit(OpCodes.Pop);
    ilgen.Emit(OpCodes.Ret);
    
  3. Concluir o método dinâmico chamando seus CreateDelegate método. Use o add acessador para adicionar o delegado à lista de invocação para o evento.

    Dim dEmitted As [Delegate] = handler.CreateDelegate(tDelegate)
    miAddHandler.Invoke(exFormAsObj, New Object() { dEmitted })
    
    Delegate dEmitted = handler.CreateDelegate(tDelegate);
    addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });
    
  4. Teste o evento.O código a seguir carrega o formulário definidos no exemplo de código.Clicando em formulário chama o manipulador de eventos predefinidos e o manipulador de evento emitido.

    Application.Run(CType(exFormAsObj, Form))
    
    Application.Run((Form) exFormAsObj);
    

Exemplo

O exemplo de código a seguir mostra como ligar um método existente a um evento usando a reflexão e também como usar o DynamicMethod classe para emitir um método em time de execução e associá-lo para um evento.

Imports System
Imports System.Reflection
Imports System.Reflection.Emit
Imports System.Windows.Forms

Class ExampleForm
    Inherits Form

    Public Sub New() 
        Me.Text = "Click me"

    End Sub 'New
End Class 'ExampleForm

Class Example

    Public Shared Sub Main() 
        Dim ex As New Example()
        ex.HookUpDelegate()
    End Sub 'Main

    Private Sub HookUpDelegate() 
        ' Load an assembly, for example using the Assembly.Load
        ' method. In this case, the executing assembly is loaded, to
        ' keep the demonstration simple.
        '
        Dim assem As [Assembly] = [Assembly].GetExecutingAssembly()

        ' Get the type that is to be loaded, and create an instance 
        ' of it. Activator.CreateInstance also has an overload that
        ' takes an array of types representing the types of the 
        ' constructor parameters, if the type you are creating does
        ' not have a parameterless constructor. The new instance
        ' is stored as type Object, to maintain the fiction that 
        ' nothing is known about the assembly. (Note that you can
        ' get the types in an assembly without knowing their names
        ' in advance.)
        '
        Dim tExForm As Type = assem.GetType("ExampleForm")
        Dim exFormAsObj As Object = _
            Activator.CreateInstance(tExForm)

        ' Get an EventInfo representing the Click event, and get the
        ' type of delegate that handles the event.
        '
        Dim evClick As EventInfo = tExForm.GetEvent("Click")
        Dim tDelegate As Type = evClick.EventHandlerType

        ' If you already have a method with the correct signature,
        ' you can simply get a MethodInfo for it. 
        '
        Dim miHandler As MethodInfo = _
            GetType(Example).GetMethod("LuckyHandler", _
                BindingFlags.NonPublic Or BindingFlags.Instance)
        ' Create an instance of the delegate. Using the overloads
        ' of CreateDelegate that take MethodInfo is recommended.
        '
        Dim d As [Delegate] = _
            [Delegate].CreateDelegate(tDelegate, Me, miHandler)

        ' Get the "add" accessor of the event and invoke it late-
        ' bound, passing in the delegate instance. This is equivalent
        ' to using the += operator in C#, or AddHandler in Visual
        ' Basic. The instance on which the "add" accessor is invoked
        ' is the form; the arguments must be passed as an array.
        '
        Dim miAddHandler As MethodInfo = evClick.GetAddMethod()
        Dim addHandlerArgs() As Object = { d }
        miAddHandler.Invoke(exFormAsObj, addHandlerArgs)

        ' Event handler methods can also be generated at run time,
        ' using lightweight dynamic methods and Reflection.Emit. 
        ' To construct an event handler, you need the return type
        ' and parameter types of the delegate. These can be obtained
        ' by examining the delegate's Invoke method. 
        '
        ' It is not necessary to name dynamic methods, so the empty 
        ' string can be used. The last argument associates the 
        ' dynamic method with the current type, giving the delegate
        ' access to all the public and private members of Example,
        ' as if it were an instance method.
        '
        Dim returnType As Type = GetDelegateReturnType(tDelegate)
        If returnType IsNot GetType(Void) Then
            Throw New ApplicationException("Delegate has a return type.")
        End If

        Dim handler As New DynamicMethod( _
            "", _
            Nothing, _
            GetDelegateParameterTypes(tDelegate), _
            GetType(Example) _
        )

        ' Generate a method body. This method loads a string, calls 
        ' the Show method overload that takes a string, pops the 
        ' return value off the stack (because the handler has no
        ' return type), and returns.
        '
        Dim ilgen As ILGenerator = handler.GetILGenerator()

        Dim showParameters As Type() = { GetType(String) }
        Dim simpleShow As MethodInfo = _
            GetType(MessageBox).GetMethod("Show", showParameters)

        ilgen.Emit(OpCodes.Ldstr, _
            "This event handler was constructed at run time.")
        ilgen.Emit(OpCodes.Call, simpleShow)
        ilgen.Emit(OpCodes.Pop)
        ilgen.Emit(OpCodes.Ret)

        ' Complete the dynamic method by calling its CreateDelegate
        ' method. Use the "add" accessor to add the delegate to
        ' the invocation list for the event.
        '
        Dim dEmitted As [Delegate] = handler.CreateDelegate(tDelegate)
        miAddHandler.Invoke(exFormAsObj, New Object() { dEmitted })

        ' Show the form. Clicking on the form causes the two
        ' delegates to be invoked.
        '
        Application.Run(CType(exFormAsObj, Form))

    End Sub

    Private Sub LuckyHandler(ByVal sender As [Object], _
        ByVal e As EventArgs) 

        MessageBox.Show("This event handler just happened to be lying around.")
    End Sub

    Private Function GetDelegateParameterTypes(ByVal d As Type) _
        As Type() 

        If d.BaseType IsNot GetType(MulticastDelegate) Then
            Throw New ApplicationException("Not a delegate.")
        End If

        Dim invoke As MethodInfo = d.GetMethod("Invoke")
        If invoke Is Nothing Then
            Throw New ApplicationException("Not a delegate.")
        End If

        Dim parameters As ParameterInfo() = invoke.GetParameters()
        ' Dimension this array Length - 1, because VB adds an extra
        ' element to zero-based arrays.
        Dim typeParameters(parameters.Length - 1) As Type
        For i As Integer = 0 To parameters.Length - 1
            typeParameters(i) = parameters(i).ParameterType
        Next i

        Return typeParameters

    End Function 


    Private Function GetDelegateReturnType(ByVal d As Type) As Type 

        If d.BaseType IsNot GetType(MulticastDelegate) Then
            Throw New ApplicationException("Not a delegate.")
        End If

        Dim invoke As MethodInfo = d.GetMethod("Invoke")
        If invoke Is Nothing Then
            Throw New ApplicationException("Not a delegate.")
        End If

        Return invoke.ReturnType

    End Function 
End Class 
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Windows.Forms;

class ExampleForm : Form 
{
    public ExampleForm() : base()
    {
        this.Text = "Click me";
    }
}

class Example
{
    public static void Main()
    {
        Example ex = new Example();
        ex.HookUpDelegate();
    }

    private void HookUpDelegate()
    {
        // Load an assembly, for example using the Assembly.Load
        // method. In this case, the executing assembly is loaded, to
        // keep the demonstration simple.
        //
        Assembly assem = Assembly.GetExecutingAssembly();

        // Get the type that is to be loaded, and create an instance 
        // of it. Activator.CreateInstance has other overloads, if
        // the type lacks a default constructor. The new instance
        // is stored as type Object, to maintain the fiction that 
        // nothing is known about the assembly. (Note that you can
        // get the types in an assembly without knowing their names
        // in advance.)
        //
        Type tExForm = assem.GetType("ExampleForm");
        Object exFormAsObj = Activator.CreateInstance(tExForm);

        // Get an EventInfo representing the Click event, and get the
        // type of delegate that handles the event.
        //
        EventInfo evClick = tExForm.GetEvent("Click");
        Type tDelegate = evClick.EventHandlerType;

        // If you already have a method with the correct signature,
        // you can simply get a MethodInfo for it. 
        //
        MethodInfo miHandler = 
            typeof(Example).GetMethod("LuckyHandler", 
                BindingFlags.NonPublic | BindingFlags.Instance);
            
        // Create an instance of the delegate. Using the overloads
        // of CreateDelegate that take MethodInfo is recommended.
        //
        Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);

        // Get the "add" accessor of the event and invoke it late-
        // bound, passing in the delegate instance. This is equivalent
        // to using the += operator in C#, or AddHandler in Visual
        // Basic. The instance on which the "add" accessor is invoked
        // is the form; the arguments must be passed as an array.
        //
        MethodInfo addHandler = evClick.GetAddMethod();
        Object[] addHandlerArgs = { d };
        addHandler.Invoke(exFormAsObj, addHandlerArgs);

        // Event handler methods can also be generated at run time,
        // using lightweight dynamic methods and Reflection.Emit. 
        // To construct an event handler, you need the return type
        // and parameter types of the delegate. These can be obtained
        // by examining the delegate's Invoke method. 
        //
        // It is not necessary to name dynamic methods, so the empty 
        // string can be used. The last argument associates the 
        // dynamic method with the current type, giving the delegate
        // access to all the public and private members of Example,
        // as if it were an instance method.
        //
        Type returnType = GetDelegateReturnType(tDelegate);
        if (returnType != typeof(void))
            throw new ApplicationException("Delegate has a return type.");

        DynamicMethod handler = 
            new DynamicMethod("", 
                              null,
                              GetDelegateParameterTypes(tDelegate),
                              typeof(Example));

        // Generate a method body. This method loads a string, calls 
        // the Show method overload that takes a string, pops the 
        // return value off the stack (because the handler has no
        // return type), and returns.
        //
        ILGenerator ilgen = handler.GetILGenerator();

        Type[] showParameters = { typeof(String) };
        MethodInfo simpleShow = 
            typeof(MessageBox).GetMethod("Show", showParameters);

        ilgen.Emit(OpCodes.Ldstr, 
            "This event handler was constructed at run time.");
        ilgen.Emit(OpCodes.Call, simpleShow);
        ilgen.Emit(OpCodes.Pop);
        ilgen.Emit(OpCodes.Ret);

        // Complete the dynamic method by calling its CreateDelegate
        // method. Use the "add" accessor to add the delegate to
        // the invocation list for the event.
        //
        Delegate dEmitted = handler.CreateDelegate(tDelegate);
        addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });

        // Show the form. Clicking on the form causes the two
        // delegates to be invoked.
        //
        Application.Run((Form) exFormAsObj);
    }

    private void LuckyHandler(Object sender, EventArgs e)
    {
        MessageBox.Show("This event handler just happened to be lying around.");
    }

    private Type[] GetDelegateParameterTypes(Type d)
    {
        if (d.BaseType != typeof(MulticastDelegate))
            throw new ApplicationException("Not a delegate.");

        MethodInfo invoke = d.GetMethod("Invoke");
        if (invoke == null)
            throw new ApplicationException("Not a delegate.");

        ParameterInfo[] parameters = invoke.GetParameters();
        Type[] typeParameters = new Type[parameters.Length];
        for (int i = 0; i < parameters.Length; i++)
        {
            typeParameters[i] = parameters[i].ParameterType;
        }
        return typeParameters;
    }

    private Type GetDelegateReturnType(Type d)
    {
        if (d.BaseType != typeof(MulticastDelegate))
            throw new ApplicationException("Not a delegate.");

        MethodInfo invoke = d.GetMethod("Invoke");
        if (invoke == null)
            throw new ApplicationException("Not a delegate.");

        return invoke.ReturnType;
    }
}

Compilando o código

  • O código contém o translation from VPE for Csharp using () instruçõesImports no Visual Basic) necessário para compilação.

  • Nenhuma referência de assembly adicionais é necessária para compilar na linha de comando.No Visual Studio, você deve adicionar uma referência a sistema.Windows.Forms.dll porque este exemplo é um aplicativo de console.

  • compilar o código na linha de comando usando csc.exe, vbc.exe ou cl.exe.Para compilar o código no Visual Studio, coloque-o em um modelo de projeto de aplicativo de console.

Consulte também

Tarefas

Como: Definir e executar métodos dinâmicos

Referência

Assembly.Load

DynamicMethod

CreateInstance

CreateDelegate

Outros recursos

Reflexão