Condividi tramite


Procedura: definire ed eseguire metodi dinamici

Aggiornamento: novembre 2007

Nelle procedure riportate di seguito viene illustrato come definire ed eseguire un metodo dinamico semplice e un metodo dinamico associato a un'istanza di una classe. Per ulteriori informazioni sui metodi dinamici, vedere la classe DynamicMethod e Scenari relativi a metodi dinamici della reflection emit.

Per definire ed eseguire un metodo dinamico

  1. Dichiarare un tipo delegato per l'esecuzione del metodo. È opportuno utilizzare un delegato generico per ridurre al minimo il numero di tipi delegati da dichiarare. Nel codice riportato di seguito vengono dichiarati due tipi delegati, uno dei quali generico, che possono essere utilizzati per il metodo 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. Creare una matrice che specifica i tipi di parametro relativi al metodo dinamico. In questo esempio l'unico parametro disponibile è un int (Integer in Visual Basic). Di conseguenza, la matrice contiene un solo elemento.

    Dim methodArgs As Type() = { GetType(Integer) }
    
    Type[] methodArgs = {typeof(int)};
    
    array<Type^>^ methodArgs = { int::typeid };
    
  3. Creare un oggetto DynamicMethod. In questo esempio il metodo è denominato SquareIt.

    Nota:

    Non è necessario assegnare un nome ai metodi dinamici, che non possono essere richiamati per nome. È possibile che più metodi dinamici abbiano lo stesso nome. Il nome viene comunque visualizzato negli stack delle chiamate e può risultare utile per operazioni di debug.

    Il tipo del valore restituito è specificato come long. Il metodo viene associato al modulo contenente la classe Example, in cui è incluso il codice di esempio. Può essere specificato qualsiasi modulo caricato. Il metodo dinamico funge da metodo static (Shared in Visual Basic) a livello di modulo

    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. Creare il corpo del metodo. In questo esempio viene utilizzato un oggetto ILGenerator per creare il codice MSIL. In alternativa, è possibile utilizzare un oggetto DynamicILInfo insieme a generatori di codice non gestito per creare il corpo del metodo relativo a un DynamicMethod.

    In questo esempio il codice MSIL carica l'argomento (int) nello stack, lo converte in un long, duplica il long ed esegue la moltiplicazione tra i due numeri. Il prodotto elevato al quadrato rimane nello stack e il metodo termina.

    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. Creare un'istanza del delegato dichiarato nel primo passaggio che rappresenta il metodo dinamico chiamando il metodo CreateDelegate. La creazione del delegato rende il metodo completo e qualsiasi successivo tentativo di modifica, ad esempio l'aggiunta di ulteriore codice MSIL, verrà ignorato. Nel codice riportato di seguito il delegato viene creato, quindi richiamato tramite un delegato generico.

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

Per definire ed eseguire un metodo dinamico associato a un oggetto

  1. Dichiarare un tipo delegato per l'esecuzione del metodo. È opportuno utilizzare un delegato generico per ridurre al minimo il numero di tipi delegati da dichiarare. Nel codice seguente viene dichiarato un delegato generico che può essere utilizzato per eseguire qualsiasi metodo con un parametro e un valore restituito o, se il delegato è associato a un oggetto, un metodo con due parametri e un valore restituito.

    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. Creare una matrice che specifica i tipi di parametro relativi al metodo dinamico. Se il delegato che rappresenta il metodo è associato a un oggetto, il primo parametro deve corrispondere al tipo a cui è associato il delegato. In questo esempio sono disponibili due parametri, uno di tipo Example e uno di tipo int (Integer in Visual Basic).

    Dim methodArgs2 As Type() = _
        { GetType(Example), GetType(Integer) }
    
    Type[] methodArgs2 = { typeof(Example), typeof(int) };
    
    array<Type^>^ methodArgs2 = { Example::typeid, int::typeid };
    
  3. Creare un oggetto DynamicMethod. In questo esempio il metodo è senza nome. Il tipo del valore restituito è specificato come int (Integer in Visual Basic). Il metodo dispone dell'accesso ai membri privati e protetti della classe 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. Creare il corpo del metodo. In questo esempio viene utilizzato un oggetto ILGenerator per creare il codice MSIL. In alternativa, è possibile utilizzare un oggetto DynamicILInfo insieme a generatori di codice non gestito per creare il corpo del metodo relativo a un DynamicMethod.

    In questo esempio il codice MSIL carica il primo argomento, un'istanza della classe Example, e lo utilizza per caricare il valore di un campo di istanza privato di tipo int. Viene caricato il secondo argomento e viene eseguita la moltiplicazione tra i due numeri. Se il prodotto è maggiore di int, il valore viene troncato e i bit più significativi vengono ignorati. Il metodo termina lasciando il valore restituito nello 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)
    
    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. Creare un'istanza del delegato dichiarato nel primo passaggio che rappresenta il metodo dinamico chiamando l'overload del metodo CreateDelegate(Type, Object). La creazione del delegato rende il metodo completo e qualsiasi successivo tentativo di modifica, ad esempio l'aggiunta di ulteriore codice MSIL, verrà ignorato.

    Nota:

    È possibile chiamare il metodo CreateDelegate più volte per creare delegati associati ad altre istanze del tipo di destinazione.

    Nel codice riportato di seguito il metodo viene associato a una nuova istanza della classe Example, il cui campo di test privato è impostato su 42. In altri termini, ogni volta che viene richiamato il delegato, l'istanza di Example viene passata al primo parametro del metodo.

    Viene utilizzato il delegato OneParameter perché il primo parametro del metodo riceve sempre l'istanza di Example. Quando il delegato viene richiamato, sarà necessario solo il secondo parametro.

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

Esempio

Nell'esempio di codice riportato di seguito vengono illustrati un metodo dinamico semplice e un metodo dinamico associato a un'istanza di una classe.

Il metodo dinamico semplice accetta un unico argomento, un valore integer a 32 bit, e ne restituisce il quadrato a 64 bit. Per richiamare il metodo, viene utilizzato un delegato generico.

Il secondo metodo dinamico dispone di due parametri, uno di tipo Example e uno di tipo int (Integer in Visual Basic). Non appena viene creato, il metodo dinamico viene associato a un'istanza di Example tramite un delegato generico che dispone di un unico argomento di tipo int. Il delegato non dispone di un argomento di tipo Example perché il primo parametro del metodo riceve sempre l'istanza associata di Example. Quando il delegato viene richiamato, verrà fornito solo l'argomento int. Questo metodo dinamico accede a un campo privato della classe Example e restituisce il prodotto tra il campo privato e l'argomento int.

Nell'esempio di codice vengono definiti i delegati che possono essere utilizzati per l'esecuzione dei metodi.

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

Compilazione del codice

  • Nel codice sono incluse le istruzioni using di C# (Imports in Visual Basic) necessarie per la compilazione.

  • Non sono necessari altri riferimenti ad assembly.

  • Compilare il codice dalla riga di comando utilizzando csc.exe, vbc.exe o cl.exe. Per compilare il codice in Visual Studio, inserirlo in un modello di progetto di applicazione console.

Vedere anche

Concetti

Scenari relativi a metodi dinamici della reflection emit

Riferimenti

DynamicMethod

Altre risorse

Utilizzo della reflection emit