Dela via


Gör så här: Koppla in en ombud med reflektion

När du använder reflektion för att läsa in och köra sammansättningar kan du inte använda språkfunktioner som C# += -operatorn eller Visual Basic AddHandler-instruktionen för att ansluta händelser. Följande procedurer visar hur du kopplar en befintlig metod till en händelse genom att hämta alla nödvändiga typer genom reflektion och hur du skapar en dynamisk metod med reflektionsemitta och kopplar den till en händelse.

Kommentar

Ett annat sätt att ansluta ett händelsehanteringsdelegat finns i kodexemplet för AddEventHandler klassens EventInfo metod.

Så här ansluter du ett ombud med reflektion

  1. Läs in en sammansättning som innehåller en typ som genererar händelser. Sammansättningar läses vanligtvis in med Assembly.Load metoden . För att hålla det här exemplet enkelt används ett härlett formulär i den aktuella sammansättningen, så GetExecutingAssembly metoden används för att läsa in den aktuella sammansättningen.

    Assembly^ assem = Example::typeid->Assembly;
    
    Assembly assem = typeof(Example).Assembly;
    
    Dim assem As Assembly = GetType(Example).Assembly
    
  2. Hämta ett Type objekt som representerar typen och skapa en instans av typen. Metoden CreateInstance(Type) används i följande kod eftersom formuläret har en parameterlös konstruktor. Det finns flera andra överlagringar av metoden CreateInstance som du kan använda om den typ du skapar inte har någon parameterlös konstruktor. Den nya instansen lagras som typ Object för att upprätthålla den fiktion som ingenting är känt om sammansättningen. (Med reflektion kan du hämta typerna i en sammansättning utan att känna till deras namn i förväg.)

    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. Hämta ett EventInfo objekt som representerar händelsen och använd EventHandlerType egenskapen för att hämta den typ av ombud som används för att hantera händelsen. I följande kod hämtas en EventInfo för Click händelsen.

    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. Hämta ett MethodInfo objekt som representerar metoden som hanterar händelsen. Den fullständiga programkoden i avsnittet Exempel senare i den här artikeln innehåller en metod som matchar ombudets EventHandler signatur, som hanterar Click händelsen, men du kan också generera dynamiska metoder vid körning. Mer information finns i den medföljande proceduren för att generera en händelsehanterare vid körning med hjälp av en dynamisk metod.

    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. Skapa en instans av ombudet med hjälp av CreateDelegate metoden . Den här metoden är statisk (Shared i Visual Basic), så ombudstypen måste anges. Vi rekommenderar att du använder överlagringarna för CreateDelegate den tagning 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. add Hämta accessor-metoden och anropa den för att ansluta händelsen. Alla händelser har en add accessor och en remove accessor som döljs av syntaxen för högnivåspråk. C# använder till exempel operatorn += för att ansluta händelser, och Visual Basic använder AddHandler-instruktionen. Följande kod hämtar add åtkomsten till händelsen och anropar den Click sent bunden och skickar in delegatinstansen. Argumenten måste skickas som en matris.

    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. Testa händelsen. Följande kod visar formuläret som definierats i kodexemplet. När du klickar på formuläret anropas händelsehanteraren.

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

Generera en händelsehanterare vid körning med hjälp av en dynamisk metod

  1. Händelsehanterarmetoder kan genereras vid körning med hjälp av lätta dynamiska metoder och reflektionsavgivande. För att skapa en händelsehanterare behöver du returtypen och parametertyperna för ombudet. Dessa kan hämtas genom att undersöka ombudets Invoke metod. Följande kod använder GetDelegateReturnType metoderna och GetDelegateParameterTypes för att hämta den här informationen. Koden för dessa metoder finns i avsnittet Exempel senare i den här artikeln.

    Det är inte nödvändigt att namnge en DynamicMethod, så att den tomma strängen kan användas. I följande kod associerar det sista argumentet den dynamiska metoden med den aktuella typen, vilket ger ombudet åtkomst till alla offentliga och privata medlemmar i Example klassen.

    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. Generera en metodtext. Den här metoden läser in en sträng, anropar överbelastningen av metoden MessageBox.Show som tar en sträng, visar returvärdet från stacken (eftersom hanteraren inte har någon returtyp) och returnerar. Mer information om hur du genererar dynamiska metoder finns i Så här definierar och kör du dynamiska metoder.

    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. Slutför den dynamiska metoden genom att anropa dess CreateDelegate metod. add Använd accessorn för att lägga till ombudet i listan över anrop för händelsen.

    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. Testa händelsen. Följande kod läser in formuläret som definierats i kodexemplet. När du klickar på formuläret anropas både den fördefinierade händelsehanteraren och den avgivna händelsehanteraren.

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

Exempel

I följande kodexempel visas hur du ansluter en befintlig metod till en händelse med reflektion och hur du använder DynamicMethod klassen för att generera en metod vid körning och koppla den till en händelse.

#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

Se även