Практическое руководство. Определение и выполнение динамических методов

В следующих процедурах показаны способы определения и выполнения простого динамического метода и динамического метода, привязанного к экземпляру класса. Дополнительные сведения о динамических методах см. в описании класса DynamicMethod и в разделе Сценарии динамических методов порождаемого отражения.

Чтобы определить и выполнить динамический метод

  1. Объявите тип делегата для выполнения метода. Рассмотрите возможность использования универсального делегата для уменьшения числа типов делегата, которые необходимо будет объявлять. В следующем коде объявляются два типа делегата, которые могут быть использованы для метода SquareIt. Один из этих типов является универсальным.

    Private Delegate Function _
        SquareItInvoker(ByVal input As Integer) As Long 
    
    Private Delegate Function _
        OneParameter(Of TReturn, TParameter0) _
        (ByVal p0 As TParameter0) As TReturn 
    
    private delegate long SquareItInvoker(int input);
    
    private delegate TReturn OneParameter<TReturn, TParameter0>
        (TParameter0 p0);
    
    private: 
        delegate long long SquareItInvoker(int input);
    
        generic<typename TReturn, typename TParameter0> 
            delegate TReturn OneParameter(TParameter0 p0);
    
  2. Создайте массив, в котором будут указаны типы параметров динамического метода. В этом примере единственным параметром является int (Integer в Visual Basic), так что массив содержит только один элемент.

    Dim methodArgs As Type() = { GetType(Integer) }
    
    Type[] methodArgs = {typeof(int)};
    
    array<Type^>^ methodArgs = { int::typeid };
    
  3. Создайте таблицу DynamicMethod. В этом примере метод называется SquareIt.

    ПримечаниеПримечание

    Нет необходимости предоставлять имена динамических методов, они не могут быть вызваны по именам.Несколько динамических методов могут иметь одинаковое имя.Однако это имя отображается в стеках вызовов и может оказаться полезным при отладке.

    Тип возвращаемого значения указан как long. Этот метод связан с модулем, содержащим класс Example, в котором расположен код примера. Может быть указан любой загруженный модуль. Динамический метод выполняется как метод static уровня модуля (Shared в Visual Basic).

    Dim squareIt As New DynamicMethod( _
        "SquareIt", _
        GetType(Long), _
        methodArgs, _
        GetType(Example).Module)
    
    DynamicMethod squareIt = new DynamicMethod(
        "SquareIt", 
        typeof(long), 
        methodArgs, 
        typeof(Example).Module);
    
    DynamicMethod^ squareIt = gcnew DynamicMethod(
        "SquareIt", 
        long long::typeid, 
        methodArgs, 
        Example::typeid->Module);
    
  4. Выпустите основную часть метода. В этом примере объект ILGenerator используется для выпуска MSIL. В качестве альтернативы объект DynamicILInfo может быть использован вместе с генераторами неуправляемого кода для выпуска основной части метода для DynamicMethod.

    MSIL в этом примере загружает аргумент, который является int, в стек, преобразует его в long, дублирует long и умножает два значения. Эти действия приводят к появлению в стеке возведенного в квадрат значения, поэтому методу остается только вернуться.

    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)
    
    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);
    
  5. Создайте экземпляр делегата (объявлен на этапе 1), который представляет динамический метод посредством вызова метода CreateDelegate. Создание делегата завершает этот метод, любые дальнейшие попытки изменить этот метод, например добавить MSIL, будут игнорироваться. В следующем коде создается и вызывается делегат с помощью универсального делегата.

    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))
    
    OneParameter<long, int> invokeSquareIt = 
        (OneParameter<long, int>)
        squareIt.CreateDelegate(typeof(OneParameter<long, int>));
    
    Console.WriteLine("123456789 squared = {0}",
        invokeSquareIt(123456789));
    
    OneParameter<long long, int>^ invokeSquareIt = 
        (OneParameter<long long, int>^)
        squareIt->CreateDelegate(OneParameter<long long, int>::typeid);
    
    Console::WriteLine("123456789 squared = {0}",
        invokeSquareIt(123456789));
    

Чтобы определить и выполнить динамический метод, привязанный к объекту

  1. Объявите тип делегата для выполнения метода. Рассмотрите возможность использования универсального делегата для уменьшения числа типов делегата, которые необходимо будет объявлять. В следующем примере кода объявляется делегат универсального типа, который может быть использован для выполнения любого метода с одним параметром и возвращаемым значением или метода с двумя параметрами и возвращаемым значением, если делегат привязан к объекту.

    Private Delegate Function _
        OneParameter(Of TReturn, TParameter0) _
        (ByVal p0 As TParameter0) As TReturn 
    
    private delegate TReturn OneParameter<TReturn, TParameter0>
        (TParameter0 p0);
    
    generic<typename TReturn, typename TParameter0> 
        delegate TReturn OneParameter(TParameter0 p0);
    
  2. Создайте массив, в котором будут указаны типы параметров динамического метода. Если делегат, представляющий метод, должен быть привязан к объекту, первый параметр должен соответствовать типу, к которому привязывается делегат. В этом примере используются два параметра: один типа Example, а другой типа int (Integer в Visual Basic).

    Dim methodArgs2 As Type() = _
        { GetType(Example), GetType(Integer) }
    
    Type[] methodArgs2 = { typeof(Example), typeof(int) };
    
    array<Type^>^ methodArgs2 = { Example::typeid, int::typeid };
    
  3. Создайте DynamicMethod. В этом примере не задано имя для данного метода. Тип возвращаемого значения указан как int (Integer в Visual Basic). Этот метод имеет доступ к закрытым и защищенным элементам класса Example.

    Dim multiplyPrivate As New DynamicMethod( _
        "", _
        GetType(Integer), _
        methodArgs2, _
        GetType(Example))
    
    DynamicMethod multiplyHidden = new DynamicMethod(
        "", 
        typeof(int), 
        methodArgs2, 
        typeof(Example));
    
    DynamicMethod^ multiplyHidden = gcnew DynamicMethod(
        "", 
        int::typeid, 
        methodArgs2, 
        Example::typeid);
    
  4. Выпустите основную часть метода. В этом примере объект ILGenerator используется для выпуска MSIL. В качестве альтернативы объект DynamicILInfo может быть использован вместе с генераторами неуправляемого кода для выпуска основной части метода для DynamicMethod.

    В этом примере MSIL загружает первый аргумент, которым является экземпляр класса Example, и использует его для загрузки значения закрытого поля экземпляра типа int. Загружается второй аргумент, после чего два числа перемножаются. Если результат превышает значение int, то результат усекается и отбрасываются старшие разряды. Метод возвращается с возвращаемым значением, содержащимся в стеке.

    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)
    
    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);
    
    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);
    
  5. Создайте экземпляр делегата (объявленного на этапе 1), который представляет динамический метод посредством вызова перегрузки метода CreateDelegate(Type, Object). Создание делегата завершает этот метод, любые дальнейшие попытки изменить этот метод, например добавить MSIL, будут игнорироваться.

    ПримечаниеПримечание

    Можно вызвать метод CreateDelegate несколько раз для создания делегатов, привязанных к другим экземплярам целевого типа.

    В следующем примере кода показано, как выполнить привязку метода к новому экземпляру класса Example, закрытое свойство проверки которого равняется 42. Т. е. при каждом вызове делегата экземпляр Example передается первому параметру метода.

    Делегат OneParameter используется, так как первый параметр метода всегда получает экземпляр Example. При вызове делегата требуется только второй параметр.

    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))
    
    OneParameter<int, int> invoke = (OneParameter<int, int>)
        multiplyHidden.CreateDelegate(
            typeof(OneParameter<int, int>), 
            new Example(42)
        );
    
    Console.WriteLine("3 * test = {0}", invoke(3));
    
    OneParameter<int, int>^ invoke = (OneParameter<int, int>^)
        multiplyHidden->CreateDelegate(
            OneParameter<int, int>::typeid, 
            gcnew Example(42)
        );
    
    Console::WriteLine("3 * test = {0}", invoke(3));
    

Пример

В следующем примере кода показано выполнение простого динамического метода и динамического метода, привязанного к экземпляру класса.

Простой динамический метод принимает один аргумент, 32-разрядное целое число, и возвращает 64-разрядное значение квадрата этого целого числа. Для вызова этого метода используется универсальный делегат.

Во втором динамическом метода содержится два параметра типа Example и int (Integer в Visual Basic). При создании динамического метода он привязывается к экземпляру Example с помощью универсального делегата, который имеет только один аргумент типа int. Делегат не имеет аргумента типа Example, потому что первый параметр метода всегда получает привязанный экземпляр Example. При вызове делегата предоставляется только аргумент int. Этот динамический метод получает доступ к закрытому полю класса Example и возвращает продукт закрытого поля и аргумента int.

В этом примере кода определяются делегаты, которые могут быть использованы для выполнения методов.

Imports System
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
' 
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
 */
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
 */

Компиляция кода

  • Код содержит операторы C# using (Imports в Visual Basic), необходимые для компиляции.

  • Дополнительные ссылки на сборки не требуются.

  • Откомпилируйте код из командной строки, используя команды csc.exe, vbc.exe или cl.exe. Чтобы откомпилировать код в Visual Studio, поместите его в шаблон проекта консольного приложения.

См. также

Ссылки

DynamicMethod

Основные понятия

Сценарии динамических методов порождаемого отражения

Другие ресурсы

Использование порождаемого отражения