Практическое руководство. Подключение делегата с помощью отраженияHow to: Hook Up a Delegate Using Reflection

При использовании отражения для загрузки и запуска сборок невозможно использовать функциональные возможности языка, такие как оператор C# += или оператор AddHandler в Visual Basic.When you use reflection to load and run assemblies, you cannot use language features like the C# += operator or the Visual Basic AddHandler statement to hook up events. В следующих процедурах показано, как подключить существующий метод к событию посредством получения всех необходимых типов через отражение и как создать динамический метод с помощью порожденного отражения и подключить этот метод к событию.The following procedures show how to hook up an existing method to an event by getting all the necessary types through reflection, and how to create a dynamic method using reflection emit and hook it up to an event.

Примечание

Другой способ подключения делегата, обрабатывающего события, см. в примере кода для метода AddEventHandler класса EventInfo.For another way to hook up an event-handling delegate, see the code example for the AddEventHandler method of the EventInfo class.

Подключение делегата с помощью отраженияTo hook up a delegate using reflection

  1. Загрузите сборку, которая содержит тип, создающий события.Load an assembly that contains a type that raises events. Как правило, сборки загружаются с помощью метода Assembly.Load.Assemblies are usually loaded with the Assembly.Load method. Чтобы не усложнять этот пример, используется производная форма из текущей сборки, чтобы для загрузки текущей сборки использовался метод GetExecutingAssembly.To keep this example simple, a derived form in the current assembly is used, so the GetExecutingAssembly method is used to load the current assembly.

    Assembly^ assem = Example::typeid->Assembly;
    
    Assembly assem = typeof(Example).Assembly;
    
    Dim assem As Assembly = GetType(Example).Assembly
    
  2. Получите объект Type, который представляет тип, и создайте экземпляр типа.Get a Type object representing the type, and create an instance of the type. Метод CreateInstance(Type) используется в следующем коде, так как эта форма имеет конструктор без параметров.The CreateInstance(Type) method is used in the following code because the form has a parameterless constructor. Существует несколько других перегрузок метода CreateInstance, которые можно использовать, если создаваемый тип не имеет конструктор без параметров.There are several other overloads of the CreateInstance method that you can use if the type you are creating does not have a parameterless constructor. Новый экземпляр сохраняется как тип Object для поддержки утверждения, что об этой сборке ничего не известно.The new instance is stored as type Object to maintain the fiction that nothing is known about the assembly. (Отражение позволяет получить типы в сборке, заведомо не зная их имена.)(Reflection allows you to get the types in an assembly without knowing their names in advance.)

    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. Получите объект EventInfo, который представляет событие, и используйте свойство EventHandlerType для получения типа делегата, используемого для обработки события.Get an EventInfo object representing the event, and use the EventHandlerType property to get the type of delegate used to handle the event. В следующем коде получается объект EventInfo для события Click.In the following code, an EventInfo for the Click event is obtained.

    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. Получите объект MethodInfo, который представляет метод, обрабатывающий событие.Get a MethodInfo object representing the method that handles the event. Полный код программы в подразделе "Пример" этого раздела содержит метод, который соответствует сигнатуре делегата EventHandler, который обрабатывает событие Click, однако также можно создавать динамические методы во время выполнения.The complete program code in the Example section later in this topic contains a method that matches the signature of the EventHandler delegate, which handles the Click event, but you can also generate dynamic methods at run time. Дополнительные сведения о создании обработчика события во время выполнения с использованием динамического метода см. в описании сопутствующей процедуры.For details, see the accompanying procedure, for generating an event handler at run time by using a dynamic method.

    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. Создайте экземпляр делегата с помощью метода CreateDelegate.Create an instance of the delegate, using the CreateDelegate method. Этот метод является статическим (Shared в Visual Basic), поэтому следует предоставить тип делегата.This method is static (Shared in Visual Basic), so the delegate type must be supplied. Рекомендуется использовать перегрузки метода CreateDelegate, принимающие MethodInfo.Using the overloads of CreateDelegate that take a MethodInfo is recommended.

    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 и вызовите его для подключения события.Get the add accessor method and invoke it to hook up the event. Все события имеют метод доступа add и метод доступа remove, которые скрыты с помощью синтаксиса в высокоуровневых языках.All events have an add accessor and a remove accessor, which are hidden by the syntax of high-level languages. Например, в C# используется оператор += для подключения событий, а в Visual Basic используется оператор AddHandler.For example, C# uses the += operator to hook up events, and Visual Basic uses the AddHandler statement. В следующем коде получается метод доступа add для события Click и вызывается с поздней привязкой, передавая в него экземпляр делегата.The following code gets the add accessor of the Click event and invokes it late-bound, passing in the delegate instance. Аргументы должны передаваться в качестве массива.The arguments must be passed as an array.

    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. Проверьте событие.Test the event. В следующем фрагменте кода показана форма, определенная в примере кода.The following code shows the form defined in the code example. Щелчок формы приводит к вызову обработчика события.Clicking the form invokes the event handler.

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

Создание обработчика событий во время выполнения с помощью динамического методаTo generate an event handler at run time by using a dynamic method

  1. Методы обработчика события могут быть созданы во время выполнения с помощью облегченных динамических методов и порождения отражения.Event-handler methods can 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. Их можно получить, просмотрев метод Invoke, относящийся к делегату.These can be obtained by examining the delegate's Invoke method. В следующем примере кода используются методы GetDelegateReturnType и GetDelegateParameterTypes для получения этих сведений.The following code uses the GetDelegateReturnType and GetDelegateParameterTypes methods to obtain this information. Код для этих методов можно найти в подразделе "Пример" этого раздела.The code for these methods can be found in the Example section later in this topic.

    Нет необходимости называть DynamicMethod, поэтому можно использовать пустую строку.It is not necessary to name a DynamicMethod, so the empty string can be used. В следующем коде последний аргумент связывает динамический метод с текущим типом, предоставляя доступ делегата ко всем открытым и закрытым элементам класса Example.In the following code, the last argument associates the dynamic method with the current type, giving the delegate access to all the public and private members of the Example class.

    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 ApplicationException("Delegate has a return type.");
        
    DynamicMethod handler = 
        new DynamicMethod("", 
                          null,
                          GetDelegateParameterTypes(tDelegate),
                          typeof(Example));
    
    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) _
    )
    
  2. Создайте основную часть метода.Generate a method body. Этот метод загружает строку, вызывает перегрузку метода MessageBox.Show, которая принимает строку, берет возвращаемое значение из стека (потому что обработчик не имеет типа возвращаемого значения) и возвращается.This method loads a string, calls the overload of the MessageBox.Show method that takes a string, pops the return value off the stack (because the handler has no return type), and returns. Дополнительные сведения о выпуске динамических методов см. в разделе Практическое руководство. Определение и выполнение динамических методов.To learn more about emitting dynamic methods, see How to: Define and Execute Dynamic Methods.

    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. Завершите динамический метод посредством вызова метода CreateDelegate.Complete the dynamic method by calling its CreateDelegate method. Используйте метод доступа add для добавления делегата в список вызова для этого события.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 });
    
    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. Проверьте событие.Test the event. В следующем фрагменте кода загружается форма, определенная в примере кода.The following code loads the form defined in the code example. Щелчок этой формы приводит к вызову предварительно определенного обработчика события и выпущенного обработчика события.Clicking the form invokes both the predefined event handler and the emitted event handler.

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

ПримерExample

В следующем примере кода показано, как подключить существующий метод к событию с помощью отражения, а также как использовать класс DynamicMethod для выпуска метода во время выполнения и подключить его к событию.The following code example shows how to hook up an existing method to an event using reflection, and also how to use the DynamicMethod class to emit a method at run time and hook it up to an event.

#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 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;
    }
}
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 'ExampleForm

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

См. такжеSee also