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

다음 절차에서는 간단한 동적 메서드 및 클래스 인스턴스에 바인딩된 동적 메서드를 정의하고 실행하는 방법을 보여 줍니다. 동적 메서드에 대한 자세한 내용은 DynamicMethod 클래스 및 리플렉션 내보내기 동적 메서드 시나리오를 참조하세요.

동적 메서드를 정의하고 실행하려면

  1. 메서드를 실행할 대리자 형식을 선언합니다. 제네릭 대리자를 사용하여 선언해야 하는 대리자 형식 수를 최소화하는 것이 좋습니다. 다음 코드는 SquareIt 메서드에 사용할 수 있는 두 개의 대리자 형식을 선언하며, 둘 중 하나는 제네릭입니다.

    private: 
        delegate long long SquareItInvoker(int input);
    
        generic<typename TReturn, typename TParameter0> 
            delegate TReturn OneParameter(TParameter0 p0);
    
    private delegate long SquareItInvoker(int input);
    
    private delegate TReturn OneParameter<TReturn, TParameter0>
        (TParameter0 p0);
    
    Private Delegate Function _
        SquareItInvoker(ByVal input As Integer) As Long
    
    Private Delegate Function _
        OneParameter(Of TReturn, TParameter0) _
        (ByVal p0 As TParameter0) As TReturn
    
  2. 동적 메서드에 대한 매개 변수 형식을 지정하는 배열을 만듭니다. 이 예제에서 유일한 매개 변수는 int(Visual Basic에서는 Integer)이므로 배열에 요소가 하나만 있습니다.

    array<Type^>^ methodArgs = { int::typeid };
    
    Type[] methodArgs = {typeof(int)};
    
    Dim methodArgs As Type() = {GetType(Integer)}
    
  3. DynamicMethod를 만듭니다. 이 예제에서 메서드 이름은 SquareIt입니다.

    참고

    동적 메서드에는 이름을 지정할 필요가 없으며, 이름으로 호출할 수 없습니다. 여러 동적 메서드가 동일한 이름을 가질 수 있습니다. 그러나 이름은 호출 스택에 표시되며 디버그하는 데 유용할 수 있습니다.

    반환 값의 형식은 long으로 지정됩니다. 메서드는 예제 코드가 들어 있는 Example 클래스를 포함하는 모듈에 연결되어 있습니다. 로드된 모든 모듈을 지정할 수 있습니다. 동적 메서드는 모듈 수준 static 메서드(Visual Basic에서는 Shared)처럼 동작합니다.

    DynamicMethod^ squareIt = gcnew DynamicMethod(
        "SquareIt", 
        long long::typeid, 
        methodArgs, 
        Example::typeid->Module);
    
    DynamicMethod squareIt = new DynamicMethod(
        "SquareIt",
        typeof(long),
        methodArgs,
        typeof(Example).Module);
    
    Dim squareIt As New DynamicMethod( _
        "SquareIt", _
        GetType(Long), _
        methodArgs, _
        GetType(Example).Module)
    
  4. 메서드 본문을 내보냅니다. 이 예제에서 ILGenerator 개체는 MSIL(Microsoft Intermediate Language)을 내보내는 데 사용됩니다. 또는 DynamicILInfo 개체를 비관리 코드 생성기와 함께 사용하여 DynamicMethod에 대한 메서드 본문을 내보낼 수 있습니다.

    이 예제의 MSIL은 int인 인수를 스택에 로드하고, long으로 변환한 다음 long을 복제하고 두 개의 숫자를 곱합니다. 이렇게 하면 스택의 거듭제곱 결과가 구해지며, 메서드가 반환하기만 하면 됩니다.

    ILGenerator^ il = squareIt->GetILGenerator();
    il->Emit(OpCodes::Ldarg_0);
    il->Emit(OpCodes::Conv_I8);
    il->Emit(OpCodes::Dup);
    il->Emit(OpCodes::Mul);
    il->Emit(OpCodes::Ret);
    
    ILGenerator il = squareIt.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Conv_I8);
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Mul);
    il.Emit(OpCodes.Ret);
    
    Dim il As ILGenerator = squareIt.GetILGenerator()
    il.Emit(OpCodes.Ldarg_0)
    il.Emit(OpCodes.Conv_I8)
    il.Emit(OpCodes.Dup)
    il.Emit(OpCodes.Mul)
    il.Emit(OpCodes.Ret)
    
  5. CreateDelegate 메서드를 호출하여 동적 메서드를 나타내는 대리자 인스턴스(1단계에서 선언됨)를 만듭니다. 대리자를 만들면 메서드가 완성되고, MSIL 추가 등 메서드를 변경하려는 이후의 모든 시도는 무시됩니다. 다음 코드는 대리자를 만들고 제네릭 대리자를 사용하여 호출합니다.

    OneParameter<long long, int>^ invokeSquareIt = 
        (OneParameter<long long, int>^)
        squareIt->CreateDelegate(OneParameter<long long, int>::typeid);
    
    Console::WriteLine("123456789 squared = {0}",
        invokeSquareIt(123456789));
    
    OneParameter<long, int> invokeSquareIt =
        (OneParameter<long, int>)
        squareIt.CreateDelegate(typeof(OneParameter<long, int>));
    
    Console.WriteLine("123456789 squared = {0}",
        invokeSquareIt(123456789));
    
    Dim invokeSquareIt As OneParameter(Of Long, Integer) = _
        CType( _
            squareIt.CreateDelegate( _
                GetType(OneParameter(Of Long, Integer))), _
            OneParameter(Of Long, Integer) _
        )
    
    Console.WriteLine("123456789 squared = {0}", _
        invokeSquareIt(123456789))
    

개체에 바인딩된 동적 메서드를 정의하고 실행하려면

  1. 메서드를 실행할 대리자 형식을 선언합니다. 제네릭 대리자를 사용하여 선언해야 하는 대리자 형식 수를 최소화하는 것이 좋습니다. 다음 코드는 매개 변수 하나가 있는 메서드 및 대리자가 개체에 바인딩된 경우 매개 변수 두 개와 반환 값이 있는 메서드를 실행하는 데 사용할 수 있는 제네릭 대리자 형식을 선언합니다.

    generic<typename TReturn, typename TParameter0> 
        delegate TReturn OneParameter(TParameter0 p0);
    
    private delegate TReturn OneParameter<TReturn, TParameter0>
        (TParameter0 p0);
    
    Private Delegate Function _
        OneParameter(Of TReturn, TParameter0) _
        (ByVal p0 As TParameter0) As TReturn
    
  2. 동적 메서드에 대한 매개 변수 형식을 지정하는 배열을 만듭니다. 메서드를 나타내는 대리자가 개체에 바인딩된 경우 첫 번째 매개 변수는 대리자가 바인딩된 형식과 일치해야 합니다. 이 예제에는 Example 형식과 int(Visual Basic에서는 Integer) 형식의 두 매개 변수가 있습니다.

    array<Type^>^ methodArgs2 = { Example::typeid, int::typeid };
    
    Type[] methodArgs2 = { typeof(Example), typeof(int) };
    
    Dim methodArgs2 As Type() = _
        {GetType(Example), GetType(Integer)}
    
  3. DynamicMethod를 만듭니다. 이 예제에서는 메서드에 이름이 없습니다. 반환 값의 형식은 int(Visual Basic에서는 Integer)로 지정됩니다. 메서드는 Example 클래스의 private 및 protected 멤버에 액세스할 수 있습니다.

    DynamicMethod^ multiplyHidden = gcnew DynamicMethod(
        "", 
        int::typeid, 
        methodArgs2, 
        Example::typeid);
    
    DynamicMethod multiplyHidden = new DynamicMethod(
        "",
        typeof(int),
        methodArgs2,
        typeof(Example));
    
    Dim multiplyPrivate As New DynamicMethod( _
        "", _
        GetType(Integer), _
        methodArgs2, _
        GetType(Example))
    
  4. 메서드 본문을 내보냅니다. 이 예제에서 ILGenerator 개체는 MSIL(Microsoft Intermediate Language)을 내보내는 데 사용됩니다. 또는 DynamicILInfo 개체를 비관리 코드 생성기와 함께 사용하여 DynamicMethod에 대한 메서드 본문을 내보낼 수 있습니다.

    이 예제의 MSIL은 Example 클래스 인스턴스인 첫 번째 인수를 로드하고 int 형식의 private 인스턴스 필드 값을 로드하는 데 사용합니다. 두 번째 인수가 로드되고, 두 개의 숫자를 곱합니다. 결과가 int보다 크면 값이 잘리고, 최상위 비트는 무시됩니다. 메서드가 반환하고 반환 값이 스택에 포함됩니다.

    ILGenerator^ ilMH = multiplyHidden->GetILGenerator();
    ilMH->Emit(OpCodes::Ldarg_0);
    
    FieldInfo^ testInfo = Example::typeid->GetField("test",
        BindingFlags::NonPublic | BindingFlags::Instance);
    
    ilMH->Emit(OpCodes::Ldfld, testInfo);
    ilMH->Emit(OpCodes::Ldarg_1);
    ilMH->Emit(OpCodes::Mul);
    ilMH->Emit(OpCodes::Ret);
    
    ILGenerator ilMH = multiplyHidden.GetILGenerator();
    ilMH.Emit(OpCodes.Ldarg_0);
    
    FieldInfo testInfo = typeof(Example).GetField("test",
        BindingFlags.NonPublic | BindingFlags.Instance);
    
    ilMH.Emit(OpCodes.Ldfld, testInfo);
    ilMH.Emit(OpCodes.Ldarg_1);
    ilMH.Emit(OpCodes.Mul);
    ilMH.Emit(OpCodes.Ret);
    
    Dim ilMP As ILGenerator = multiplyPrivate.GetILGenerator()
    ilMP.Emit(OpCodes.Ldarg_0)
    
    Dim testInfo As FieldInfo = _
        GetType(Example).GetField("test", _
            BindingFlags.NonPublic Or BindingFlags.Instance)
    
    ilMP.Emit(OpCodes.Ldfld, testInfo)
    ilMP.Emit(OpCodes.Ldarg_1)
    ilMP.Emit(OpCodes.Mul)
    ilMP.Emit(OpCodes.Ret)
    
  5. CreateDelegate(Type, Object) 메서드 오버로드를 호출하여 동적 메서드를 나타내는 대리자 인스턴스(1단계에서 선언됨)를 만듭니다. 대리자를 만들면 메서드가 완성되고, MSIL 추가 등 메서드를 변경하려는 이후의 모든 시도는 무시됩니다.

    참고

    CreateDelegate 메서드를 여러 번 호출하여 대상 형식의 다른 인스턴스에 바인딩된 대리자를 만들 수 있습니다.

    다음 코드는 private 테스트 필드가 42로 설정된 Example 클래스의 새 인스턴스에 메서드를 바인딩합니다. 즉, 대리자를 호출할 때마다 Example 인스턴스가 메서드의 첫 번째 매개 변수에 전달됩니다.

    메서드의 첫 번째 매개 변수는 항상 Example 인스턴스를 받기 때문에 OneParameter 대리자가 사용됩니다. 대리자를 호출하는 경우 두 번째 매개 변수만 필요합니다.

    OneParameter<int, int>^ invoke = (OneParameter<int, int>^)
        multiplyHidden->CreateDelegate(
            OneParameter<int, int>::typeid, 
            gcnew Example(42)
        );
    
    Console::WriteLine("3 * test = {0}", invoke(3));
    
    OneParameter<int, int> invoke = (OneParameter<int, int>)
        multiplyHidden.CreateDelegate(
            typeof(OneParameter<int, int>),
            new Example(42)
        );
    
    Console.WriteLine("3 * test = {0}", invoke(3));
    
    Dim invoke As OneParameter(Of Integer, Integer) = _
        CType( _
            multiplyPrivate.CreateDelegate( _
                GetType(OneParameter(Of Integer, Integer)), _
                new Example(42) _
            ), _
            OneParameter(Of Integer, Integer) _
        )
    
    Console.WriteLine("3 * test = {0}", invoke(3))
    

예제

다음 코드 예제에서는 간단한 동적 메서드 및 클래스 인스턴스에 바인딩된 동적 메서드를 보여 줍니다.

간단한 동적 메서드는 32비트 정수인 인수 하나를 사용하고 해당 정수의 64비트 거듭제곱을 반환합니다. 제네릭 대리자는 메서드를 호출하는 데 사용됩니다.

두 번째 동적 메서드에는 Example 형식과 int(Visual Basic에서는 Integer) 형식의 두 매개 변수가 있습니다. 동적 메서드를 만들면 int 형식의 인수 하나가 있는 제네릭 대리자를 사용하여 Example 인스턴스에 바인딩됩니다. 메서드의 첫 번째 매개 변수는 항상 Example의 바인딩된 인스턴스를 받기 때문에 대리자에 Example 형식의 인수가 없습니다. 대리자를 호출할 때 int 인수만 제공됩니다. 이 동적 메서드는 Example 클래스의 private 필드에 액세스하고 private 필드와 int 인수의 곱을 반환합니다.

코드 예제에서는 메서드 실행에 사용할 수 있는 대리자를 정의합니다.

using namespace System;
using namespace System::Reflection;
using namespace System::Reflection::Emit;

public ref class Example
{
    // The following constructor and private field are used to
    // demonstrate a method bound to an object.
private:
    int test;
    
public:
    Example(int test) { this->test = test; }

    // Declare delegates that can be used to execute the completed 
    // SquareIt dynamic method. The OneParameter delegate can be 
    // used to execute any method with one parameter and a return
    // value, or a method with two parameters and a return value
    // if the delegate is bound to an object.
    //
private: 
    delegate long long SquareItInvoker(int input);

    generic<typename TReturn, typename TParameter0> 
        delegate TReturn OneParameter(TParameter0 p0);

public:
    static void Main()
    {
        // Example 1: A simple dynamic method.
        //
        // Create an array that specifies the parameter types for the
        // dynamic method. In this example the only parameter is an 
        // int, so the array has only one element.
        //
        array<Type^>^ methodArgs = { int::typeid };

        // Create a DynamicMethod. In this example the method is
        // named SquareIt. It is not necessary to give dynamic 
        // methods names. They cannot be invoked by name, and two
        // dynamic methods can have the same name. However, the 
        // name appears in calls stacks and can be useful for
        // debugging. 
        //
        // In this example the return type of the dynamic method is
        // long long. The method is associated with the module that 
        // contains the Example class. Any loaded module could be
        // specified. The dynamic method is like a module-level
        // static method.
        //
        DynamicMethod^ squareIt = gcnew DynamicMethod(
            "SquareIt", 
            long long::typeid, 
            methodArgs, 
            Example::typeid->Module);

        // Emit the method body. In this example ILGenerator is used
        // to emit the MSIL. DynamicMethod has an associated type
        // DynamicILInfo that can be used in conjunction with 
        // unmanaged code generators.
        //
        // The MSIL loads the argument, which is an int, onto the 
        // stack, converts the int to a long long, duplicates the top
        // item on the stack, and multiplies the top two items on the
        // stack. This leaves the squared number on the stack, and 
        // all the method has to do is return.
        //
        ILGenerator^ il = squareIt->GetILGenerator();
        il->Emit(OpCodes::Ldarg_0);
        il->Emit(OpCodes::Conv_I8);
        il->Emit(OpCodes::Dup);
        il->Emit(OpCodes::Mul);
        il->Emit(OpCodes::Ret);

        // Create a delegate that represents the dynamic method. 
        // Creating the delegate completes the method, and any further 
        // attempts to change the method (for example, by adding more
        // MSIL) are ignored. The following code uses a generic 
        // delegate that can produce delegate types matching any
        // single-parameter method that has a return type.
        //
        OneParameter<long long, int>^ invokeSquareIt = 
            (OneParameter<long long, int>^)
            squareIt->CreateDelegate(OneParameter<long long, int>::typeid);

        Console::WriteLine("123456789 squared = {0}",
            invokeSquareIt(123456789));

        // Example 2: A dynamic method bound to an instance.
        //
        // Create an array that specifies the parameter types for a
        // dynamic method. If the delegate representing the method
        // is to be bound to an object, the first parameter must 
        // match the type the delegate is bound to. In the following
        // code the bound instance is of the Example class. 
        //
        array<Type^>^ methodArgs2 = { Example::typeid, int::typeid };

        // Create a DynamicMethod. In this example the method has no
        // name. The return type of the method is int. The method 
        // has access to the protected and private data of the 
        // Example class.
        //
        DynamicMethod^ multiplyHidden = gcnew DynamicMethod(
            "", 
            int::typeid, 
            methodArgs2, 
            Example::typeid);

        // Emit the method body. In this example ILGenerator is used
        // to emit the MSIL. DynamicMethod has an associated type
        // DynamicILInfo that can be used in conjunction with 
        // unmanaged code generators.
        //
        // The MSIL loads the first argument, which is an instance of
        // the Example class, and uses it to load the value of a 
        // private instance field of type int. The second argument is
        // loaded, and the two numbers are multiplied. If the result
        // is larger than int, the value is truncated and the most 
        // significant bits are discarded. The method returns, with
        // the return value on the stack.
        //
        ILGenerator^ ilMH = multiplyHidden->GetILGenerator();
        ilMH->Emit(OpCodes::Ldarg_0);

        FieldInfo^ testInfo = Example::typeid->GetField("test",
            BindingFlags::NonPublic | BindingFlags::Instance);

        ilMH->Emit(OpCodes::Ldfld, testInfo);
        ilMH->Emit(OpCodes::Ldarg_1);
        ilMH->Emit(OpCodes::Mul);
        ilMH->Emit(OpCodes::Ret);

        // Create a delegate that represents the dynamic method. 
        // Creating the delegate completes the method, and any further 
        // attempts to change the method � for example, by adding more
        // MSIL � are ignored. 
        // 
        // The following code binds the method to a new instance
        // of the Example class whose private test field is set to 42.
        // That is, each time the delegate is invoked the instance of
        // Example is passed to the first parameter of the method.
        //
        // The delegate OneParameter is used, because the first
        // parameter of the method receives the instance of Example.
        // When the delegate is invoked, only the second parameter is
        // required. 
        //
        OneParameter<int, int>^ invoke = (OneParameter<int, int>^)
            multiplyHidden->CreateDelegate(
                OneParameter<int, int>::typeid, 
                gcnew Example(42)
            );

        Console::WriteLine("3 * test = {0}", invoke(3));
    }
};

void main()
{
    Example::Main();
}
/* This code example produces the following output:

123456789 squared = 15241578750190521
3 * test = 126
 */
using System;
using System.Reflection;
using System.Reflection.Emit;

public class Example
{
    // The following constructor and private field are used to
    // demonstrate a method bound to an object.
    private int test;
    public Example(int test) { this.test = test; }

    // Declare delegates that can be used to execute the completed
    // SquareIt dynamic method. The OneParameter delegate can be
    // used to execute any method with one parameter and a return
    // value, or a method with two parameters and a return value
    // if the delegate is bound to an object.
    //
    private delegate long SquareItInvoker(int input);

    private delegate TReturn OneParameter<TReturn, TParameter0>
        (TParameter0 p0);

    public static void Main()
    {
        // Example 1: A simple dynamic method.
        //
        // Create an array that specifies the parameter types for the
        // dynamic method. In this example the only parameter is an
        // int, so the array has only one element.
        //
        Type[] methodArgs = {typeof(int)};

        // Create a DynamicMethod. In this example the method is
        // named SquareIt. It is not necessary to give dynamic
        // methods names. They cannot be invoked by name, and two
        // dynamic methods can have the same name. However, the
        // name appears in calls stacks and can be useful for
        // debugging.
        //
        // In this example the return type of the dynamic method
        // is long. The method is associated with the module that
        // contains the Example class. Any loaded module could be
        // specified. The dynamic method is like a module-level
        // static method.
        //
        DynamicMethod squareIt = new DynamicMethod(
            "SquareIt",
            typeof(long),
            methodArgs,
            typeof(Example).Module);

        // Emit the method body. In this example ILGenerator is used
        // to emit the MSIL. DynamicMethod has an associated type
        // DynamicILInfo that can be used in conjunction with
        // unmanaged code generators.
        //
        // The MSIL loads the argument, which is an int, onto the
        // stack, converts the int to a long, duplicates the top
        // item on the stack, and multiplies the top two items on the
        // stack. This leaves the squared number on the stack, and
        // all the method has to do is return.
        //
        ILGenerator il = squareIt.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Conv_I8);
        il.Emit(OpCodes.Dup);
        il.Emit(OpCodes.Mul);
        il.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method.
        // Creating the delegate completes the method, and any further
        // attempts to change the method (for example, by adding more
        // MSIL) are ignored. The following code uses a generic
        // delegate that can produce delegate types matching any
        // single-parameter method that has a return type.
        //
        OneParameter<long, int> invokeSquareIt =
            (OneParameter<long, int>)
            squareIt.CreateDelegate(typeof(OneParameter<long, int>));

        Console.WriteLine("123456789 squared = {0}",
            invokeSquareIt(123456789));

        // Example 2: A dynamic method bound to an instance.
        //
        // Create an array that specifies the parameter types for a
        // dynamic method. If the delegate representing the method
        // is to be bound to an object, the first parameter must
        // match the type the delegate is bound to. In the following
        // code the bound instance is of the Example class.
        //
        Type[] methodArgs2 = { typeof(Example), typeof(int) };

        // Create a DynamicMethod. In this example the method has no
        // name. The return type of the method is int. The method
        // has access to the protected and private data of the
        // Example class.
        //
        DynamicMethod multiplyHidden = new DynamicMethod(
            "",
            typeof(int),
            methodArgs2,
            typeof(Example));

        // Emit the method body. In this example ILGenerator is used
        // to emit the MSIL. DynamicMethod has an associated type
        // DynamicILInfo that can be used in conjunction with
        // unmanaged code generators.
        //
        // The MSIL loads the first argument, which is an instance of
        // the Example class, and uses it to load the value of a
        // private instance field of type int. The second argument is
        // loaded, and the two numbers are multiplied. If the result
        // is larger than int, the value is truncated and the most
        // significant bits are discarded. The method returns, with
        // the return value on the stack.
        //
        ILGenerator ilMH = multiplyHidden.GetILGenerator();
        ilMH.Emit(OpCodes.Ldarg_0);

        FieldInfo testInfo = typeof(Example).GetField("test",
            BindingFlags.NonPublic | BindingFlags.Instance);

        ilMH.Emit(OpCodes.Ldfld, testInfo);
        ilMH.Emit(OpCodes.Ldarg_1);
        ilMH.Emit(OpCodes.Mul);
        ilMH.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method.
        // Creating the delegate completes the method, and any further
        // attempts to change the method — for example, by adding more
        // MSIL — are ignored.
        //
        // The following code binds the method to a new instance
        // of the Example class whose private test field is set to 42.
        // That is, each time the delegate is invoked the instance of
        // Example is passed to the first parameter of the method.
        //
        // The delegate OneParameter is used, because the first
        // parameter of the method receives the instance of Example.
        // When the delegate is invoked, only the second parameter is
        // required.
        //
        OneParameter<int, int> invoke = (OneParameter<int, int>)
            multiplyHidden.CreateDelegate(
                typeof(OneParameter<int, int>),
                new Example(42)
            );

        Console.WriteLine("3 * test = {0}", invoke(3));
    }
}
/* This code example produces the following output:

123456789 squared = 15241578750190521
3 * test = 126
 */
Imports System.Reflection
Imports System.Reflection.Emit

Public Class Example

    ' The following constructor and private field are used to
    ' demonstrate a method bound to an object.
    '
    Private test As Integer
    Public Sub New(ByVal test As Integer)
        Me.test = test
    End Sub

    ' Declare delegates that can be used to execute the completed 
    ' SquareIt dynamic method. The OneParameter delegate can be 
    ' used to execute any method with one parameter and a return
    ' value, or a method with two parameters and a return value
    ' if the delegate is bound to an object.
    '
    Private Delegate Function _
        SquareItInvoker(ByVal input As Integer) As Long

    Private Delegate Function _
        OneParameter(Of TReturn, TParameter0) _
        (ByVal p0 As TParameter0) As TReturn

    Public Shared Sub Main()

        ' Example 1: A simple dynamic method.
        '
        ' Create an array that specifies the parameter types for the
        ' dynamic method. In this example the only parameter is an 
        ' Integer, so the array has only one element.
        '
        Dim methodArgs As Type() = {GetType(Integer)}

        ' Create a DynamicMethod. In this example the method is
        ' named SquareIt. It is not necessary to give dynamic 
        ' methods names. They cannot be invoked by name, and two
        ' dynamic methods can have the same name. However, the 
        ' name appears in calls stacks and can be useful for
        ' debugging. 
        '
        ' In this example the return type of the dynamic method
        ' is Long. The method is associated with the module that 
        ' contains the Example class. Any loaded module could be
        ' specified. The dynamic method is like a module-level
        ' Shared method.
        '
        Dim squareIt As New DynamicMethod( _
            "SquareIt", _
            GetType(Long), _
            methodArgs, _
            GetType(Example).Module)

        ' Emit the method body. In this example ILGenerator is used
        ' to emit the MSIL. DynamicMethod has an associated type
        ' DynamicILInfo that can be used in conjunction with 
        ' unmanaged code generators.
        '
        ' The MSIL loads the argument, which is an Integer, onto the 
        ' stack, converts the Integer to a Long, duplicates the top
        ' item on the stack, and multiplies the top two items on the
        ' stack. This leaves the squared number on the stack, and 
        ' all the method has to do is return.
        '
        Dim il As ILGenerator = squareIt.GetILGenerator()
        il.Emit(OpCodes.Ldarg_0)
        il.Emit(OpCodes.Conv_I8)
        il.Emit(OpCodes.Dup)
        il.Emit(OpCodes.Mul)
        il.Emit(OpCodes.Ret)

        ' Create a delegate that represents the dynamic method. 
        ' Creating the delegate completes the method, and any further 
        ' attempts to change the method (for example, by adding more
        ' MSIL) are ignored. The following code uses a generic 
        ' delegate that can produce delegate types matching any
        ' single-parameter method that has a return type.
        '
        Dim invokeSquareIt As OneParameter(Of Long, Integer) = _
            CType( _
                squareIt.CreateDelegate( _
                    GetType(OneParameter(Of Long, Integer))), _
                OneParameter(Of Long, Integer) _
            )

        Console.WriteLine("123456789 squared = {0}", _
            invokeSquareIt(123456789))


        ' Example 2: A dynamic method bound to an instance.
        '
        ' Create an array that specifies the parameter types for a
        ' dynamic method. If the delegate representing the method
        ' is to be bound to an object, the first parameter must 
        ' match the type the delegate is bound to. In the following
        ' code the bound instance is of the Example class. 
        '
        Dim methodArgs2 As Type() = _
            {GetType(Example), GetType(Integer)}

        ' Create a DynamicMethod. In this example the method has no
        ' name. The return type of the method is Integer. The method 
        ' has access to the protected and private members of the 
        ' Example class. 
        '
        Dim multiplyPrivate As New DynamicMethod( _
            "", _
            GetType(Integer), _
            methodArgs2, _
            GetType(Example))

        ' Emit the method body. In this example ILGenerator is used
        ' to emit the MSIL. DynamicMethod has an associated type
        ' DynamicILInfo that can be used in conjunction with 
        ' unmanaged code generators.
        '
        ' The MSIL loads the first argument, which is an instance of
        ' the Example class, and uses it to load the value of a 
        ' private instance field of type Integer. The second argument 
        ' is loaded, and the two numbers are multiplied. If the result
        ' is larger than Integer, the value is truncated and the most 
        ' significant bits are discarded. The method returns, with
        ' the return value on the stack.
        '
        Dim ilMP As ILGenerator = multiplyPrivate.GetILGenerator()
        ilMP.Emit(OpCodes.Ldarg_0)

        Dim testInfo As FieldInfo = _
            GetType(Example).GetField("test", _
                BindingFlags.NonPublic Or BindingFlags.Instance)

        ilMP.Emit(OpCodes.Ldfld, testInfo)
        ilMP.Emit(OpCodes.Ldarg_1)
        ilMP.Emit(OpCodes.Mul)
        ilMP.Emit(OpCodes.Ret)

        ' Create a delegate that represents the dynamic method. 
        ' Creating the delegate completes the method, and any further 
        ' attempts to change the method  for example, by adding more
        ' MSIL  are ignored. 
        ' 
        ' The following code binds the method to a new instance
        ' of the Example class whose private test field is set to 42.
        ' That is, each time the delegate is invoked the instance of
        ' Example is passed to the first parameter of the method.
        '
        ' The delegate OneParameter is used, because the first
        ' parameter of the method receives the instance of Example.
        ' When the delegate is invoked, only the second parameter is
        ' required. 
        '
        Dim invoke As OneParameter(Of Integer, Integer) = _
            CType( _
                multiplyPrivate.CreateDelegate( _
                    GetType(OneParameter(Of Integer, Integer)), _
                    new Example(42) _
                ), _
                OneParameter(Of Integer, Integer) _
            )

        Console.WriteLine("3 * test = {0}", invoke(3))

    End Sub

End Class

' This code example produces the following output:
'
'123456789 squared = 15241578750190521
'3 * test = 126
' 

참조