Guide pratique pour définir et exécuter des méthodes dynamiquesHow to: Define and Execute Dynamic Methods

Les procédures suivantes montrent comment définir et exécuter une méthode dynamique simple et une méthode dynamique liée à une instance d’une classe.The following procedures show how to define and execute a simple dynamic method and a dynamic method bound to an instance of a class. Pour plus d’informations sur les méthodes dynamiques, consultez la classe DynamicMethod et Scénarios de méthodes dynamiques avec Émission de réflexion.For more information on dynamic methods, see the DynamicMethod class and Reflection Emit Dynamic Method Scenarios.

Pour définir et exécuter une méthode dynamiqueTo define and execute a dynamic method

  1. Déclarez un type délégué pour exécuter la méthode.Declare a delegate type to execute the method. Vous pouvez utiliser un délégué générique pour réduire le nombre de types délégués que vous devez déclarer.Consider using a generic delegate to minimize the number of delegate types you need to declare. Le code suivant déclare deux types délégués qui peuvent être utilisés pour la méthode SquareIt, et l’un d’eux est générique.The following code declares two delegate types that could be used for the SquareIt method, and one of them is generic.

    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. Créez un tableau qui spécifie les types de paramètre de la méthode dynamique.Create an array that specifies the parameter types for the dynamic method. Dans cet exemple, le seul paramètre est un int (Integer en Visual Basic). Le tableau n’a donc qu’un seul élément.In this example, the only parameter is an int (Integer in Visual Basic), so the array has only one element.

    array<Type^>^ methodArgs = { int::typeid };
    
    Type[] methodArgs = {typeof(int)};
    
    Dim methodArgs As Type() = { GetType(Integer) }
    
  3. Créer un DynamicMethod.Create a DynamicMethod. Dans cet exemple, la méthode se nomme SquareIt.In this example the method is named SquareIt.

    Notes

    Il n’est pas nécessaire de nommer les méthodes dynamiques. Elles ne peuvent pas être appelées par nom.It is not necessary to give dynamic methods names, and they cannot be invoked by name. Plusieurs méthodes dynamiques peuvent avoir le même nom.Multiple dynamic methods can have the same name. Toutefois, le nom apparaît dans les piles des appels et peut être utile pour le débogage.However, the name appears in call stacks and can be useful for debugging.

    Le type de la valeur de retour est spécifié comme long.The type of the return value is specified as long. La méthode est associée au module qui contient la classe Example, qui contient l’exemple de code.The method is associated with the module that contains the Example class, which contains the example code. Vous pourriez spécifier n’importe quel module chargé.Any loaded module could be specified. La méthode dynamique agit comme une méthode static au niveau du module (Shared en Visual Basic).The dynamic method acts like a module-level static method (Shared in Visual Basic).

    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. Émettez le corps de méthode.Emit the method body. Dans cet exemple, un objet ILGenerator est utilisé pour émettre le code MSIL (Microsoft Intermediate Language).In this example, an ILGenerator object is used to emit the Microsoft intermediate language (MSIL). Vous pourriez également utiliser un objet DynamicILInfo conjointement avec des générateurs de code non managé pour émettre le corps de méthode pour un DynamicMethod.Alternatively, a DynamicILInfo object can be used in conjunction with unmanaged code generators to emit the method body for a DynamicMethod.

    Le code MSIL de cet exemple charge l’argument (qui est un int) dans la pile, le convertit en long, duplique le long et multiplie les deux nombres.The MSIL in this example loads the argument, which is an int, onto the stack, converts it to a long, duplicates the long, and multiplies the two numbers. Cela laisse le résultat au carré sur la pile, et il suffit à la méthode de retourner.This leaves the squared result 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);
    
    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. Créez une instance du délégué (déclaré à l’étape 1) qui représente la méthode dynamique en appelant la méthode CreateDelegate.Create an instance of the delegate (declared in step 1) that represents the dynamic method by calling the CreateDelegate method. La création du délégué achève la méthode, et toute tentative supplémentaire de changement de la méthode (par exemple l’ajout de code MSIL) est ignorée.Creating the delegate completes the method, and any further attempts to change the method — for example, adding more MSIL — are ignored. Le code suivant crée le délégué et l’appelle, à l’aide d’un délégué générique.The following code creates the delegate and invokes it, using a generic delegate.

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

Pour définir et exécuter une méthode dynamique liée à un objetTo define and execute a dynamic method that is bound to an object

  1. Déclarez un type délégué pour exécuter la méthode.Declare a delegate type to execute the method. Vous pouvez utiliser un délégué générique pour réduire le nombre de types délégués que vous devez déclarer.Consider using a generic delegate to minimize the number of delegate types you need to declare. Le code suivant déclare un type délégué générique qui peut être utilisé pour exécuter n’importe quelle méthode avec un paramètre et une valeur de retour, ou une méthode avec deux paramètres et une valeur de retour si le délégué est lié à un objet.The following code declares a generic delegate type that 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.

    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. Créez un tableau qui spécifie les types de paramètre de la méthode dynamique.Create an array that specifies the parameter types for the dynamic method. Si le délégué représentant la méthode doit être lié à un objet, le premier paramètre doit correspondre au type auquel le délégué est lié.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. Cet exemple contient deux paramètres, de type Example et int (Integer en Visual Basic).In this example, there are two parameters, of type Example and type int (Integer in Visual Basic).

    array<Type^>^ methodArgs2 = { Example::typeid, int::typeid };
    
    Type[] methodArgs2 = { typeof(Example), typeof(int) };
    
    Dim methodArgs2 As Type() = _
        { GetType(Example), GetType(Integer) }
    
  3. Créer un DynamicMethod.Create a DynamicMethod. Dans cet exemple, la méthode n’a pas de nom.In this example the method has no name. Le type de la valeur de retour est spécifié comme int (Integer en Visual Basic).The type of the return value is specified as int (Integer in Visual Basic). La méthode a accès aux membres privés et protégés de la classe Example.The method has access to the private and protected members of the Example class.

    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. Émettez le corps de méthode.Emit the method body. Dans cet exemple, un objet ILGenerator est utilisé pour émettre le code MSIL (Microsoft Intermediate Language).In this example, an ILGenerator object is used to emit the Microsoft intermediate language (MSIL). Vous pourriez également utiliser un objet DynamicILInfo conjointement avec des générateurs de code non managé pour émettre le corps de méthode pour un DynamicMethod.Alternatively, a DynamicILInfo object can be used in conjunction with unmanaged code generators to emit the method body for a DynamicMethod.

    Le code MSIL de cet exemple charge le premier argument, qui est une instance de la classe Example, et l’utilise pour charger la valeur d’un champ d’instance privé de type int.The MSIL in this example 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. Le deuxième argument est chargé, et les deux nombres sont multipliés.The second argument is loaded, and the two numbers are multiplied. Si le résultat est supérieur à int, la valeur est tronquée et les bits les plus significatifs sont ignorés.If the result is larger than int, the value is truncated and the most significant bits are discarded. La méthode retourne, avec la valeur de retour sur la pile.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);
    
    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. Créez une instance du délégué (déclaré à l’étape 1) qui représente la méthode dynamique en appelant la surcharge de méthode CreateDelegate(Type, Object).Create an instance of the delegate (declared in step 1) that represents the dynamic method by calling the CreateDelegate(Type, Object) method overload. La création du délégué achève la méthode, et toute tentative supplémentaire de changement de la méthode (par exemple l’ajout de code MSIL) est ignorée.Creating the delegate completes the method, and any further attempts to change the method — for example, adding more MSIL — are ignored.

    Notes

    Vous pouvez appeler la méthode CreateDelegate plusieurs fois afin de créer des délégués liés à d’autres instances du type cible.You can call the CreateDelegate method multiple times to create delegates bound to other instances of the target type.

    Le code suivant lie la méthode à une nouvelle instance de la classe Example dont le champ de test privé a la valeur 42.The following code binds the method to a new instance of the Example class whose private test field is set to 42. Autrement dit, chaque fois que le délégué est appelé, l’instance de Example est passée au premier paramètre de la méthode.That is, each time the delegate is invoked the instance of Example is passed to the first parameter of the method.

    Le délégué OneParameter est utilisé, car le premier paramètre de la méthode reçoit toujours l’instance de Example.The delegate OneParameter is used because the first parameter of the method always receives the instance of Example. Quand le délégué est appelé, seul le deuxième paramètre est nécessaire.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));
    
    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))
    

ExempleExample

L’exemple de code suivant montre une méthode dynamique simple et une méthode dynamique liée à une instance d’une classe.The following code example demonstrates a simple dynamic method and a dynamic method bound to an instance of a class.

La méthode dynamique simple prend un argument, un entier 32 bits, et retourne le carré 64 bits de cet entier.The simple dynamic method takes one argument, a 32-bit integer, and returns the 64-bit square of that integer. Un délégué générique est utilisé pour appeler la méthode.A generic delegate is used to invoke the method.

La deuxième méthode dynamique a deux paramètres, de type Example et int (Integer en Visual Basic).The second dynamic method has two parameters, of type Example and type int (Integer in Visual Basic). Quand la méthode dynamique a été créée, elle est liée à une instance de Example, à l’aide d’un délégué générique qui a un argument de type int.When the dynamic method has been created, it is bound to an instance of Example, using a generic delegate that has one argument of type int. Le délégué n’a pas d’argument de type Example, car le premier paramètre de la méthode reçoit toujours l’instance liée de Example.The delegate does not have an argument of type Example because the first parameter of the method always receives the bound instance of Example. Quand le délégué est appelé, seul l’argument int est fourni.When the delegate is invoked, only the int argument is supplied. Cette méthode dynamique accède à un champ privé de la classe Example et retourne le produit du champ privé et l’argument int.This dynamic method accesses a private field of the Example class and returns the product of the private field and the int argument.

L’exemple de code définit des délégués qui peuvent être utilisés pour exécuter les méthodes.The code example defines delegates that can be used to execute the methods.

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
' 

Voir aussiSee also