Exportar (0) Imprimir
Expandir todo
Este artículo proviene de un motor de traducción automática. Mueva el puntero sobre las frases del artículo para ver el texto original. Más información.
Traducción
Original

Cómo: Enlazar un delegado mediante la reflexión

Cuando se utiliza la reflexión para cargar y ejecutar ensamblados, no se pueden utilizar características del lenguaje como el operador += de C# o la instrucción AddHandler de Visual Basic para enlazar eventos. Los procedimientos siguientes muestran cómo enlazar un método existente a un evento obteniendo todos los tipos necesarios mediante reflexión y cómo crear un método dinámico utilizando la emisión de la reflexión y enlazarlo a un evento.

Nota Nota

Para conocer otra manera de enlazar un delegado de control de eventos, vea el ejemplo de código del método AddEventHandler de la clase EventInfo.

Para enlazar un delegado mediante la reflexión

  1. Cargue un ensamblado que contenga un tipo que provoque eventos. Los ensamblados normalmente se cargan con el método Assembly.Load. Para mantener la simplicidad de este ejemplo, se utiliza un formulario derivado del ensamblado actual, de manera que se utilice el método GetExecutingAssembly para cargar el ensamblado actual.

    
    Assembly assem = Assembly.GetExecutingAssembly();
    
    
    
  2. Obtenga un objeto Type que represente el tipo y cree una instancia de dicho tipo. El método CreateInstance(Type) se utiliza en el código siguiente porque el formulario tiene un constructor predeterminado. Hay varias otras sobrecargas del método CreateInstance que puede utilizar si el tipo que está creando no tiene un constructor predeterminado. La nueva instancia se almacena como tipo Object para mantener la ficción de que no se sabe nada sobre el ensamblado. (La reflexión le permite obtener los tipos de un ensamblado sin conocer de antemano sus nombres.)

    
    Type tExForm = assem.GetType("ExampleForm");
    Object exFormAsObj = Activator.CreateInstance(tExForm);
    
    
    
  3. Obtenga un objeto EventInfo que represente el evento y utilice la propiedad EventHandlerType para obtener el tipo de delegado utilizado para controlar el evento. En el código siguiente, se obtiene EventInfo para el evento Click.

    
    EventInfo evClick = tExForm.GetEvent("Click");
    Type tDelegate = evClick.EventHandlerType;
    
    
    
  4. Obtenga un objeto MethodInfo que representa el método que controla el evento. Todo el código del programa de la sección Ejemplo, que se encuentra más adelante en este tema, contiene un método que coincide con la signatura del delegado EventHandler, que controla el evento Click, pero también puede generar métodos dinámicos en tiempo de ejecución. Para obtener detalles, vea el procedimiento de acompañamiento para generar un controlador de eventos en tiempo de ejecución usando un método dinámico.

    
    MethodInfo miHandler = 
        typeof(Example).GetMethod("LuckyHandler", 
            BindingFlags.NonPublic | BindingFlags.Instance);
    
    
    
  5. Cree una instancia del delegado utilizando el método CreateDelegate. Este método es estático (Shared en Visual Basic), por lo que se debe proporcionar el tipo de delegado. Se recomienda utilizar las sobrecargas de CreateDelegate que toman MethodInfo.

    
    Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
    
    
    
  6. Obtenga el método del descriptor de acceso add e invóquelo para enlazar el evento. Todos los eventos tienen un descriptor de acceso add y un descriptor de acceso remove, que son ocultados por la sintaxis de los lenguajes de alto nivel. Por ejemplo, C# utiliza el operador += para enlazar eventos y Visual Basic utiliza la instrucción AddHandler. El código siguiente obtiene el descriptor de acceso add del evento Click y lo invoca enlazado en tiempo de ejecución, pasando la instancia del delegado. Los argumentos se deben pasar como una matriz.

    
    MethodInfo addHandler = evClick.GetAddMethod();
    Object[] addHandlerArgs = { d };
    addHandler.Invoke(exFormAsObj, addHandlerArgs);
    
    
    
  7. Pruebe el evento. El código siguiente muestra el formulario definido en el ejemplo de código. Al hacer clic en el formulario, se invoca el controlador de eventos.

    
    Application.Run((Form) exFormAsObj);
    
    
    

Para generar un controlador de eventos en tiempo de ejecución utilizando un método dinámico

  1. utilizando métodos dinámicos ligeros y la emisión de reflexión se pueden generar métodos de controlador de eventos en tiempo de ejecución. Para construir un controlador de eventos, es necesario conocer el tipo de valor devuelto y los tipos de parámetros del delegado. Éstos se pueden obtener examinando el método Invoke del delegado. El código siguiente utiliza los métodos GetDelegateReturnType y GetDelegateParameterTypes para obtener esta información. El código para estos métodos se puede encontrar más adelante en este tema, en la sección Ejemplo.

    No es necesario asignar nombre a DynamicMethod, por lo que se puede utilizar la cadena vacía. En el código siguiente, el último argumento asocia el método dinámico con el tipo actual, dando al delegado acceso a todos los miembros públicos y privados de la clase 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. Genere un cuerpo del método. Este método carga una cadena, llama a la sobrecarga del método MessageBox.Show que toma una cadena, saca el valor devuelto de la pila (porque el controlador no tiene tipo de valor devuelto) y vuelve. Para obtener más información sobre cómo emitir métodos dinámicos, vea Cómo: Definir y ejecutar métodos dinámicos.

    
    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. Finalice el método dinámico llamando a su método CreateDelegate. Utilice el descriptor de acceso add para agregar el delegado a la lista de invocación del evento.

    
    Delegate dEmitted = handler.CreateDelegate(tDelegate);
    addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });
    
    
    
  4. Pruebe el evento. El código siguiente carga el formulario definido en el ejemplo de código. Al hacer clic en el formulario se invocan el controlador de eventos predefinido y el controlador de eventos emitido.

    
    Application.Run((Form) exFormAsObj);
    
    
    

El siguiente ejemplo de código muestra cómo enlazar un método existente con un evento utilizando la reflexión y cómo utilizar la clase DynamicMethod para emitir un método en tiempo de ejecución y enlazarlo con un evento.


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


  • El código contiene las instrucciones using de C# (Imports en Visual Basic) necesarias para la compilación.

  • No se requieren referencias de ensamblado adicionales para compilar desde la línea de comandos. En Visual Studio, debe agregar una referencia a System.Windows.Forms.dll porque este ejemplo es una aplicación de consola.

  • Compile el código de la línea de comandos mediante csc.exe, vbc.exe, o cl.exe. Para compilar el código en Visual Studio, póngalo en una plantilla de proyecto de aplicación de consola.

Adiciones de comunidad

AGREGAR
Mostrar:
© 2015 Microsoft