动态方法可以使用 ILGenerator 对象发出 Microsoft 中间语言 (MSIL)。此外,动态方法还可以使用 DynamicILInfo 对象处理元数据标记和允许复杂客户端执行自己的 MSIL 生成的范围。
动态方法对需要生成运行时代码以保证性能的情形十分有用。 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);
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>));
// 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);
// 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 */