다음을 통해 공유


방법: 리플렉션을 사용하여 대리자 후크

리플렉션을 사용하여 어셈블리를 로드하고 실행할 때 C# += 연산자나 Visual Basic AddHandler 문과 같은 언어 기능을 사용하여 이벤트를 후크할 수는 없습니다. 다음 절차에서는 리플렉션을 통해 필요한 모든 형식을 가져와 기존 메서드를 이벤트에 후크하는 방법과 리플렉션 내보내기를 사용하여 동적 메서드를 만들고 이벤트에 후크하는 방법을 보여 줍니다.

참고참고

이벤트 처리 대리자를 후크하는 다른 방법은 EventInfo 클래스의 AddEventHandler 메서드에 대한 코드 예제를 참조하십시오.

리플렉션을 사용하여 대리자를 후크하려면

  1. 이벤트를 발생시키는 형식이 포함된 어셈블리를 로드합니다. 어셈블리는 일반적으로 Assembly.Load 메서드와 함께 로드됩니다. 이 예제를 간단히 유지하기 위해 현재 어셈블리의 파생된 폼을 사용하므로 현재 어셈블리를 로드하는 데 GetExecutingAssembly 메서드를 사용합니다.

    Dim assem As [Assembly] = [Assembly].GetExecutingAssembly()
    
    Assembly assem = Assembly.GetExecutingAssembly();
    
    Assembly^ assem = Assembly::GetExecutingAssembly();
    
  2. 형식을 나타내는 Type 개체를 가져온 다음 해당 형식의 인스턴스를 만듭니다. 폼에 기본 생성자가 있으므로 다음 코드에서는 CreateInstance(Type) 메서드를 사용합니다. 만들려는 형식에 기본 생성자가 없는 경우 사용할 수 있는 CreateInstance 메서드의 몇 가지 다른 오버로드가 있습니다. 새 인스턴스는 Object 형식으로 저장되어 어셈블리에 대해 알려진 내용이 없다는 fiction을 유지합니다. (리플렉션을 사용하면 형식의 이름을 미리 알지 않아도 어셈블리에서 형식을 가져올 수 있습니다.)

    Dim tExForm As Type = assem.GetType("ExampleForm")
    Dim exFormAsObj As Object = _
        Activator.CreateInstance(tExForm)
    
    Type tExForm = assem.GetType("ExampleForm");
    Object exFormAsObj = Activator.CreateInstance(tExForm);
    
    Type^ tExForm = assem->GetType("ExampleForm");
    Object^ exFormAsObj = Activator::CreateInstance(tExForm);
    
  3. 이벤트를 나타내는 EventInfo 개체를 가져온 다음 EventHandlerType 속성을 사용하여 이벤트 처리에 사용된 대리자의 형식을 가져옵니다. 다음 코드에서 Click 이벤트에 대해 EventInfo를 가져옵니다.

    Dim evClick As EventInfo = tExForm.GetEvent("Click")
    Dim tDelegate As Type = evClick.EventHandlerType
    
    EventInfo evClick = tExForm.GetEvent("Click");
    Type tDelegate = evClick.EventHandlerType;
    
    EventInfo^ evClick = tExForm->GetEvent("Click");
    Type^ tDelegate = evClick->EventHandlerType;
    
  4. 이벤트를 처리하는 메서드를 나타내는 MethodInfo 개체를 가져옵니다. 이 항목의 뒷부분에 나오는 예제 단원의 완성된 프로그램 코드에 Click 이벤트를 처리하는 EventHandler 대리자의 시그니처와 일치하는 메서드가 들어 있지만, 런타임에 동적 메서드를 생성할 수도 있습니다. 자세한 내용은 다음에 나오는 절차 동적 메서드를 사용하여 런타임에 이벤트 처리기를 생성하려면을 참조하십시오.

    Dim miHandler As MethodInfo = _
        GetType(Example).GetMethod("LuckyHandler", _
            BindingFlags.NonPublic Or BindingFlags.Instance)
    
    MethodInfo miHandler = 
        typeof(Example).GetMethod("LuckyHandler", 
            BindingFlags.NonPublic | BindingFlags.Instance);
    
    MethodInfo^ miHandler =
        Type::GetType("Example")->GetMethod("LuckyHandler",
            BindingFlags::NonPublic | BindingFlags::Instance);
    
  5. CreateDelegate 메서드를 사용하여 대리자의 인스턴스를 만듭니다. 이 메서드는 정적(Visual Basic의 경우 Shared)이므로 대리자 형식이 제공되어야 합니다. MethodInfo를 사용하는 CreateDelegate의 오버로드를 사용하는 것이 좋습니다.

    Dim d As [Delegate] = _
        [Delegate].CreateDelegate(tDelegate, Me, miHandler)
    
    Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
    
    Delegate^ d = Delegate::CreateDelegate(tDelegate, this, miHandler);
    
  6. add 접근자 메서드를 가져오고 이 메서드를 호출하여 이벤트에 후크합니다. 모든 이벤트에는 상위 수준 언어의 구문에서 숨겨지는 add 접근자와 remove 접근자가 있습니다. 예를 들어, C#에서는 += 연산자를 사용하여 이벤트를 후크하고 Visual Basic에서는 AddHandler 문을 사용하여 이벤트를 후크합니다. 다음 코드에서는 Click 이벤트의 add 접근자를 가져오고 런타임에 바인딩된 호출을 사용하여 대리자 인스턴스를 전달합니다. 인수는 배열로 전달되어야 합니다.

    Dim miAddHandler As MethodInfo = evClick.GetAddMethod()
    Dim addHandlerArgs() As Object = { d }
    miAddHandler.Invoke(exFormAsObj, addHandlerArgs)
    
    MethodInfo addHandler = evClick.GetAddMethod();
    Object[] addHandlerArgs = { d };
    addHandler.Invoke(exFormAsObj, addHandlerArgs);
    
    MethodInfo^ addHandler = evClick->GetAddMethod();
    array<Object^>^ addHandlerArgs = { d };
    addHandler->Invoke(exFormAsObj, addHandlerArgs);
    
  7. 이벤트를 테스트합니다. 다음 코드에서는 코드 예제에서 정의된 폼을 보여 줍니다. 해당 폼을 클릭하면 이벤트 처리기가 호출됩니다.

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

동적 메서드를 사용하여 런타임에 이벤트 처리기를 생성하려면

  1. 간단한 동적 메서드와 리플렉션 내보내기를 사용하여 런타임에 이벤트 처리기 메서드를 생성할 수 있습니다. 이벤트 처리기를 생성하려면 대리자의 반환 형식과 매개 변수 형식이 필요합니다. 이러한 형식은 대리자의 Invoke 메서드를 검사하여 가져올 수 있습니다. 다음 코드에서는 GetDelegateReturnType 메서드와 GetDelegateParameterTypes 메서드를 사용하여 이 정보를 가져옵니다. 이러한 메서드의 코드는 이 항목의 뒷부분에 나오는 예제 단원에서 찾을 수 있습니다.

    DynamicMethod의 이름을 지정할 필요가 없으므로 빈 문자열을 사용할 수 있습니다. 다음 코드에서는 마지막 인수가 동적 메서드와 현재 형식을 연결하여 대리자에게 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) _
    )
    
    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));
    
    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);
    
  2. 메서드 본문을 생성합니다. 이 메서드는 문자열을 로드하고, 문자열을 사용하는 MessageBox.Show 메서드의 오버로드를 호출하고, 스택에서 반환 값을 팝한 다음(처리기에 반환 형식이 없으므로) 반환됩니다. 동적 메서드 내보내기에 대한 자세한 내용은 방법: 동적 메서드 정의 및 실행을 참조하십시오.

    Dim ilgen As ILGenerator = handler.GetILGenerator()
    
    Dim showParameters As Type() = { GetType(String) }
    Dim simpleShow As MethodInfo = _
        GetType(MessageBox).GetMethod("Show", showParameters)
    
    ilgen.Emit(OpCodes.Ldstr, _
        "This event handler was constructed at run time.")
    ilgen.Emit(OpCodes.Call, simpleShow)
    ilgen.Emit(OpCodes.Pop)
    ilgen.Emit(OpCodes.Ret)
    
    ILGenerator ilgen = handler.GetILGenerator();
    
    Type[] showParameters = { typeof(String) };
    MethodInfo simpleShow = 
        typeof(MessageBox).GetMethod("Show", showParameters);
    
    ilgen.Emit(OpCodes.Ldstr, 
        "This event handler was constructed at run time.");
    ilgen.Emit(OpCodes.Call, simpleShow);
    ilgen.Emit(OpCodes.Pop);
    ilgen.Emit(OpCodes.Ret);
    
    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);
    
  3. CreateDelegate 메서드를 호출하여 동적 메서드를 완료합니다. add 접근자를 사용하여 해당 이벤트의 호출 목록에 대리자를 추가합니다.

    Dim dEmitted As [Delegate] = handler.CreateDelegate(tDelegate)
    miAddHandler.Invoke(exFormAsObj, New Object() { dEmitted })
    
    Delegate dEmitted = handler.CreateDelegate(tDelegate);
    addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });
    
    Delegate^ dEmitted = handler->CreateDelegate(tDelegate);
    addHandler->Invoke(exFormAsObj, gcnew array<Object^> { dEmitted });
    
  4. 이벤트를 테스트합니다. 다음 코드에서는 코드 예제에서 정의된 폼을 로드합니다. 해당 폼을 클릭하면 미리 정의된 이벤트 처리기와 내보낸 이벤트 처리기가 호출됩니다.

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

예제

다음 코드 예제에서는 리플렉션을 사용하여 기존 메서드를 이벤트에 후크하는 방법과 DynamicMethod 클래스를 사용하여 런타임에 메서드를 내보내고 이벤트에 후크하는 방법을 보여 줍니다.

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

Class ExampleForm
    Inherits Form

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

    End Sub 'New
End Class 'ExampleForm

Class Example

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

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

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

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

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

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

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

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

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

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

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

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

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

    End Sub

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

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

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

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

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

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

        Return typeParameters

    End Function 


    Private Function GetDelegateReturnType(ByVal d As Type) As Type 

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

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

        Return invoke.ReturnType

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        return invoke.ReturnType;
    }
}
#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 = 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 =
            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();
}

코드 컴파일

  • 이 코드에는 컴파일에 필요한 C# using 문(Visual Basic의 경우 Imports)이 포함되어 있습니다.

  • 명령줄에서 컴파일하는 데 추가 어셈블리 참조는 필요하지 않습니다. 이 예제는 콘솔 응용 프로그램이므로 Visual Studio에서 참조를 System.Windows.Forms.dll에 추가해야 합니다.

  • csc.exe, vbc.exe 또는 cl.exe를 사용하여 명령줄에서 코드를 컴파일합니다. Visual Studio에서 코드를 컴파일하려면 콘솔 응용 프로젝트 템플릿에 코드를 삽입합니다.

참고 항목

작업

방법: 동적 메서드 정의 및 실행

참조

Assembly.Load

DynamicMethod

CreateInstance

CreateDelegate

개념

리플렉션