Procedura: Associare un delegato usando la reflection

Quando si usa la reflection per caricare ed eseguire assembly, non è possibile usare funzionalità del linguaggio come l'operatore C# += o l'istruzione AddHandler di Visual Basic per associare gli eventi. Le procedure seguenti illustrano come associare un metodo esistente a un evento recuperando tutti i tipi necessari tramite reflection e come creare un metodo dinamico usando reflection emit e associarlo a un evento.

Nota

Per un metodo alternativo per associare un delegato per la gestione degli eventi, vedere l'esempio di codice per il metodo AddEventHandler della classe EventInfo.

Per associare un delegato tramite reflection

  1. Caricare un assembly contenente un tipo che genera eventi. Gli assembly vengono in genere caricati con il metodo Assembly.Load. Per evitare che l'esempio diventi troppo complesso, viene usato un form derivato nell'assembly corrente, ovvero viene usato il metodo GetExecutingAssembly per caricare l'assembly corrente.

    Assembly^ assem = Example::typeid->Assembly;
    
    Assembly assem = typeof(Example).Assembly;
    
    Dim assem As Assembly = GetType(Example).Assembly
    
  2. Ottenere un oggetto Type che rappresenta il tipo e creare un'istanza del tipo. Nel codice seguente viene usato il metodo CreateInstance(Type) perché il modulo ha un costruttore senza parametri. Se il tipo creato non ha un costruttore senza parametri, è possibile usare vari altri overload del metodo CreateInstance. Affinché sembri che non sia disponibile alcuna informazione sull'assembly, la nuova istanza viene memorizzata come tipo Object. Infatti, la reflection consente di ottenere i tipi in un assembly senza che sia necessario conoscerne i nomi in anticipo.

    Type^ tExForm = assem->GetType("ExampleForm");
    Object^ exFormAsObj = Activator::CreateInstance(tExForm);
    
    Type tExForm = assem.GetType("ExampleForm");
    Object exFormAsObj = Activator.CreateInstance(tExForm);
    
    Dim tExForm As Type = assem.GetType("ExampleForm")
    Dim exFormAsObj As Object = _
        Activator.CreateInstance(tExForm)
    
  3. Ottenere un oggetto EventInfo che rappresenta l'evento e usare la proprietà EventHandlerType per recuperare il tipo del delegato usato per la gestione dell'evento. Nel codice seguente viene recuperato EventInfo per l'evento Click.

    EventInfo^ evClick = tExForm->GetEvent("Click");
    Type^ tDelegate = evClick->EventHandlerType;
    
    EventInfo evClick = tExForm.GetEvent("Click");
    Type tDelegate = evClick.EventHandlerType;
    
    Dim evClick As EventInfo = tExForm.GetEvent("Click")
    Dim tDelegate As Type = evClick.EventHandlerType
    
  4. Ottenere un oggetto MethodInfo che rappresenta il metodo che gestisce l'evento. Il codice del programma completo nella sezione Example più avanti in questo articolo contiene un metodo che corrisponde alla firma del EventHandler delegato, che gestisce l'evento Click , ma è anche possibile generare metodi dinamici in fase di esecuzione. Per informazioni dettagliate, vedere la procedura associata per generare un gestore eventi in fase di esecuzione tramite un metodo dinamico.

    MethodInfo^ miHandler =
        Type::GetType("Example")->GetMethod("LuckyHandler",
            BindingFlags::NonPublic | BindingFlags::Instance);
    
    MethodInfo miHandler =
        typeof(Example).GetMethod("LuckyHandler",
            BindingFlags.NonPublic | BindingFlags.Instance);
    
    Dim miHandler As MethodInfo = _
        GetType(Example).GetMethod("LuckyHandler", _
            BindingFlags.NonPublic Or BindingFlags.Instance)
    
  5. Creare un'istanza del delegato usando il metodo CreateDelegate. Poiché il metodo è statico (Shared in Visual Basic), è necessario specificare il tipo delegato. Si consiglia di usare gli overload del metodo CreateDelegate che accettano MethodInfo.

    Delegate^ d = Delegate::CreateDelegate(tDelegate, this, miHandler);
    
    Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
    
    Dim d As [Delegate] = _
        [Delegate].CreateDelegate(tDelegate, Me, miHandler)
    
  6. Ottenere il metodo della funzione di accesso add e richiamarlo per associare l'evento. Tutti gli eventi hanno una funzione di accesso add e una funzione di accesso remove nascoste dalla sintassi dei linguaggi di alto livello. Ad esempio, C# usa l'operatore += per associare gli eventi e Visual Basic usa l'istruzione AddHandler. Il codice seguente ottiene la funzione di accesso add dell'evento Click e la richiama con associazione tardiva passando l'istanza del delegato. Gli argomenti devono essere passati come matrice.

    MethodInfo^ addHandler = evClick->GetAddMethod();
    array<Object^>^ addHandlerArgs = { d };
    addHandler->Invoke(exFormAsObj, addHandlerArgs);
    
    MethodInfo addHandler = evClick.GetAddMethod();
    Object[] addHandlerArgs = { d };
    addHandler.Invoke(exFormAsObj, addHandlerArgs);
    
    Dim miAddHandler As MethodInfo = evClick.GetAddMethod()
    Dim addHandlerArgs() As Object = {d}
    miAddHandler.Invoke(exFormAsObj, addHandlerArgs)
    
  7. Verificare l'evento. Il codice seguente illustra il form definito nell'esempio di codice. Se si fa clic sul form, viene richiamato il gestore dell'evento.

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

Generare un gestore eventi in fase di esecuzione usando un metodo dinamico

  1. I metodi per la gestione degli eventi possono essere generati in fase di esecuzione usando metodi dinamici leggeri e reflection emit. Per costruire un gestore dell'evento, sono necessari il tipo restituito e i tipi di parametro del delegato, che possono essere ottenuti esaminando il metodo Invoke del delegato. Il codice seguente usa i metodi GetDelegateReturnType e GetDelegateParameterTypes per ottenere queste informazioni. Il codice per questi metodi è disponibile nella sezione Esempio più avanti in questo articolo.

    Poiché non è necessario assegnare un nome a DynamicMethod, è possibile usare la stringa vuota. Nel codice seguente l'ultimo argomento associa il metodo dinamico al tipo corrente, concedendo al delegato l'accesso a tutti i membri pubblici e privati della classe Example.

    Type^ returnType = GetDelegateReturnType(tDelegate);
    if (returnType != void::typeid)
        throw gcnew ApplicationException("Delegate has a return type.");
        
    DynamicMethod^ handler =
        gcnew DynamicMethod("",
                          nullptr,
                          GetDelegateParameterTypes(tDelegate),
                          Example::typeid);
    
    Type returnType = GetDelegateReturnType(tDelegate);
    if (returnType != typeof(void))
        throw new ArgumentException("Delegate has a return type.", nameof(d));
    
    DynamicMethod handler =
        new DynamicMethod("",
                          null,
                          GetDelegateParameterTypes(tDelegate),
                          typeof(Example));
    
    Dim returnType As Type = GetDelegateReturnType(tDelegate)
    If returnType IsNot GetType(Void) Then
        Throw New ArgumentException("Delegate has a return type.", NameOf(d))
    End If
    
    Dim handler As New DynamicMethod( _
        "", _
        Nothing, _
        GetDelegateParameterTypes(tDelegate), _
        GetType(Example) _
    )
    
  2. Generare il corpo di un metodo. Il metodo carica una stringa, chiama l'overload del metodo MessageBox.Show che accetta una stringa, estrae il valore restituito dallo stack perché il gestore non ha alcun tipo restituito e termina. Per altre informazioni sulla creazione di metodi dinamici, vedere Procedura: Definire ed eseguire metodi dinamici.

    ILGenerator^ ilgen = handler->GetILGenerator();
    
    array<Type^>^ showParameters = { String::typeid };
    MethodInfo^ simpleShow =
        MessageBox::typeid->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);
    
    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)
    
  3. Completare il metodo dinamico chiamando il relativo metodo CreateDelegate. Usare la funzione di accesso add per aggiungere il delegato all'elenco di chiamate per l'evento.

    Delegate^ dEmitted = handler->CreateDelegate(tDelegate);
    addHandler->Invoke(exFormAsObj, gcnew array<Object^> { dEmitted });
    
    Delegate dEmitted = handler.CreateDelegate(tDelegate);
    addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });
    
    Dim dEmitted As [Delegate] = handler.CreateDelegate(tDelegate)
    miAddHandler.Invoke(exFormAsObj, New Object() {dEmitted})
    
  4. Verificare l'evento. Il codice seguente carica il form definito nell'esempio di codice. Fare clic sul form per richiamare il gestore dell'evento predefinito e il gestore creato.

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

Esempio

L'esempio di codice seguente illustra come associare un metodo esistente a un evento tramite reflection e come usare la classe DynamicMethod per creare un metodo in fase di esecuzione e associarlo a un evento.

#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Reflection;
using namespace System::Reflection::Emit;
using namespace System::Windows::Forms;

public ref class ExampleForm : public Form
{
public:
    ExampleForm() : Form()
    {
        this->Text = "Click me";
    }
};

public ref class Example
{
public:
    static void Main()
    {
        Example^ ex = gcnew 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 = Example::typeid->Assembly;

        // 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 =
            Type::GetType("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();
        array<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 != void::typeid)
            throw gcnew ApplicationException("Delegate has a return type.");
            
        DynamicMethod^ handler =
            gcnew DynamicMethod("",
                              nullptr,
                              GetDelegateParameterTypes(tDelegate),
                              Example::typeid);

        // 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();

        array<Type^>^ showParameters = { String::typeid };
        MethodInfo^ simpleShow =
            MessageBox::typeid->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, gcnew array<Object^> { dEmitted });

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

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

    array<Type^>^ GetDelegateParameterTypes(Type^ d)
    {
        if (d->BaseType != MulticastDelegate::typeid)
            throw gcnew ApplicationException("Not a delegate.");

        MethodInfo^ invoke = d->GetMethod("Invoke");
        if (invoke == nullptr)
            throw gcnew ApplicationException("Not a delegate.");

        array<ParameterInfo^>^ parameters = invoke->GetParameters();
        array<Type^>^ typeParameters = gcnew array<Type^>(parameters->Length);
        for (int i = 0; i < parameters->Length; i++)
        {
            typeParameters[i] = parameters[i]->ParameterType;
        }
        return typeParameters;
    }

    Type^ GetDelegateReturnType(Type^ d)
    {
        if (d->BaseType != MulticastDelegate::typeid)
            throw gcnew ApplicationException("Not a delegate.");

        MethodInfo^ invoke = d->GetMethod("Invoke");
        if (invoke == nullptr)
            throw gcnew ApplicationException("Not a delegate.");

        return invoke->ReturnType;
    }
};

int main()
{
    Example::Main();
}
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 = typeof(Example).Assembly;

        // 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 ArgumentException("Delegate has a return type.", nameof(d));

        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 ArgumentException("Not a delegate.", nameof(d));

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

        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 ArgumentException("Not a delegate.", nameof(d));

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

        return invoke.ReturnType;
    }
}
Imports System.Reflection
Imports System.Reflection.Emit
Imports System.Windows.Forms

Class ExampleForm
    Inherits Form

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

    End Sub
End Class

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

    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 = GetType(Example).Assembly

        ' 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 ArgumentException("Delegate has a return type.", NameOf(d))
        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 ArgumentException("Not a delegate.", NameOf(d))
        End If

        Dim invoke As MethodInfo = d.GetMethod("Invoke")
        If invoke Is Nothing Then
            Throw New ArgumentException("Not a delegate.", NameOf(d))
        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 ArgumentException("Not a delegate.", NameOf(d))
        End If

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

        Return invoke.ReturnType

    End Function
End Class

Vedi anche