DynamicMethod 类

本文介绍如何使用 C# 的反射发射来动态生成方法,并通过几个示例展示了具体的实现过程。包括了如何创建动态方法、生成 IL 代码、定义委托类型及参数等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 public delegate String MyMethod(String str);
        private void GenerateMethod()
        {
            Type[] argsType = { typeof(String) };
            DynamicMethod dm = new DynamicMethod("MyMethod1",
            typeof(String),
            argsType,
            typeof(Form1).Module);//public string MyMethod1(string s)
            ILGenerator il = dm.GetILGenerator();//{
            il.Emit(OpCodes.Ldstr, "hello:");//string a="hello:";
            il.Emit(OpCodes.Ldarg_0);//把参数推到堆栈上
            il.Emit(OpCodes.Call, typeof(String).GetMethod("Concat", new Type[] { typeof(String), typeof(String) }));//string.Concat(a,s);
            il.Emit(OpCodes.Ret);//return string.Concat(a,s);}
            MyMethod myMethod = (MyMethod)dm.CreateDelegate(typeof(MyMethod));
            
            MessageBox.Show(myMethod("my friends"));
           
        }
        private void GenerateMethodTwo()
        {
            DynamicMethod dm = new DynamicMethod("Test", null,
              new Type[] { typeof(string) }, typeof(string).Module);
            ILGenerator il = dm.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);//把参数推到堆栈上
            MethodInfo call = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
            il.Emit(OpCodes.Call, call);//执行Console.WriteLine方法
            il.Emit(OpCodes.Ret);//结束返回
            Action<string> test = (Action<string>)dm.CreateDelegate(typeof(Action<string>));
            test("henry");

            //下面Test1方法和Test完成的方法是一样的,但IL似乎有些不同.
            //主要体现变量设置,对于变量的位置也会影响指令
            dm = new DynamicMethod("Test1", null,
                new Type[] { typeof(string) }, typeof(string).Module);
            il = dm.GetILGenerator();
            il.DeclareLocal(typeof(string));//定义变量
            il.Emit(OpCodes.Ldarg_0);//把参数推到堆栈上
            il.Emit(OpCodes.Stloc_0);//把值保存到索引为0的变量里
            il.Emit(OpCodes.Ldloc_0);//把索引为0的变量推到堆栈上
            call = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
            il.Emit(OpCodes.Call, call);//执行Console.WriteLine方法
            il.Emit(OpCodes.Ret);
            test = (Action<string>)dm.CreateDelegate(typeof(Action<string>));
            test("henry");

            //对于下面的方法大家自己推一下,其实很简单.
            //如果看起来有不明白,不防copy到vs.net上然后看指令描述信息:)
            dm = new DynamicMethod("Test2", null,
               new Type[] { typeof(string) }, typeof(string).Module);
            il = dm.GetILGenerator();
            il.DeclareLocal(typeof(string));//声明一个string局部变量
            il.Emit(OpCodes.Ldstr, "你好 ");//推送一个字符串引用
            il.Emit(OpCodes.Ldarg_0);//把索引为0参数推到堆栈上
            call = typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) });
            il.Emit(OpCodes.Call, call);
            il.Emit(OpCodes.Stloc_0);//得到的值存入局部变量
            il.Emit(OpCodes.Ldloc_0);//加载局部变量到堆栈
            call = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
            il.Emit(OpCodes.Call, call);
            il.Emit(OpCodes.Ret);//执行方法
            test = (Action<string>)dm.CreateDelegate(typeof(Action<string>));
            test("henry");
            //Console.Read();
        }
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Globalization;

public class Test
{
    // Declare a delegate type that can be used to execute the completed
    // dynamic method. 
    private delegate int HelloDelegate(string msg, int ret);

    public static void Main()
    {
        // Create an array that specifies the types of the parameters
        // of the dynamic method. This dynamic method has a String
        // parameter and an Integer parameter.
        Type[] helloArgs = {typeof(string), typeof(int)};

        // Create a dynamic method with the name "Hello", a return type
        // of Integer, and two parameters whose types are specified by
        // the array helloArgs. Create the method in the module that
        // defines the String class.
        DynamicMethod hello = new DynamicMethod("Hello", 
            typeof(int), 
            helloArgs, 
            typeof(string).Module);

        // Create an array that specifies the parameter types of the
        // overload of Console.WriteLine to be used in Hello.
        Type[] writeStringArgs = {typeof(string)};
        // Get the overload of Console.WriteLine that has one
        // String parameter.
        MethodInfo writeString = typeof(Console).GetMethod("WriteLine", 
            writeStringArgs);

        // Get an ILGenerator and emit a body for the dynamic method,
        // using a stream size larger than the IL that will be
        // emitted.
        ILGenerator il = hello.GetILGenerator(256);
        // Load the first argument, which is a string, onto the stack.
        il.Emit(OpCodes.Ldarg_0);
        // Call the overload of Console.WriteLine that prints a string.
        il.EmitCall(OpCodes.Call, writeString, null);
        // The Hello method returns the value of the second argument;
        // to do this, load the onto the stack and return.
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Ret);

        // Display MethodAttributes for the dynamic method, set when 
        // the dynamic method was created.
        Console.WriteLine("\r\nMethod Attributes: {0}", hello.Attributes);

        // Display the calling convention of the dynamic method, set when the 
        // dynamic method was created.
        Console.WriteLine("\r\nCalling convention: {0}", hello.CallingConvention);

        // Display the declaring type, which is always null for dynamic
        // methods.
        if (hello.DeclaringType==null)
        {
            Console.WriteLine("\r\nDeclaringType is always null for dynamic methods.");
        }
        else
        {
            Console.WriteLine("DeclaringType: {0}", hello.DeclaringType);
        }

        // Display the default value for InitLocals.
        if (hello.InitLocals)
        {
            Console.Write("\r\nThis method contains verifiable code.");
        }
        else
        {
            Console.Write("\r\nThis method contains unverifiable code.");
        }
        Console.WriteLine(" (InitLocals = {0})", hello.InitLocals);

        // Display the module specified when the dynamic method was created.
        Console.WriteLine("\r\nModule: {0}", hello.Module);

        // Display the name specified when the dynamic method was created.
        // Note that the name can be blank.
        Console.WriteLine("\r\nName: {0}", hello.Name);

        // For dynamic methods, the reflected type is always null.
        if (hello.ReflectedType==null)
        {
            Console.WriteLine("\r\nReflectedType is null.");
        }
        else
        {
            Console.WriteLine("\r\nReflectedType: {0}", hello.ReflectedType);
        }

        if (hello.ReturnParameter==null)
        {
            Console.WriteLine("\r\nMethod has no return parameter.");
        }
        else
        {
            Console.WriteLine("\r\nReturn parameter: {0}", hello.ReturnParameter);
        }

        // If the method has no return type, ReturnType is System.Void.
        Console.WriteLine("\r\nReturn type: {0}", hello.ReturnType);

        // ReturnTypeCustomAttributes returns an ICustomeAttributeProvider
        // that can be used to enumerate the custom attributes of the
        // return value. At present, there is no way to set such custom
        // attributes, so the list is empty.
        if (hello.ReturnType == typeof(void))
        {
            Console.WriteLine("The method has no return type.");
        }
        else
        {
            ICustomAttributeProvider caProvider = hello.ReturnTypeCustomAttributes;
            object[] returnAttributes = caProvider.GetCustomAttributes(true);
            if (returnAttributes.Length==0)
            {
                Console.WriteLine("\r\nThe return type has no custom attributes.");
            }
            else
            {
                Console.WriteLine("\r\nThe return type has the following custom attributes:");
                foreach( object attr in returnAttributes )
                {
                    Console.WriteLine("\t{0}", attr.ToString());
                }
            }
        }

        Console.WriteLine("\r\nToString: {0}", hello.ToString());

        // Add parameter information to the dynamic method. (This is not
        // necessary, but can be useful for debugging.) For each parameter,
        // identified by position, supply the parameter attributes and a 
        // parameter name.
        ParameterBuilder parameter1 = hello.DefineParameter(
            1, 
            ParameterAttributes.In, 
            "message"
        );
        ParameterBuilder parameter2 = hello.DefineParameter(
            2, 
            ParameterAttributes.In, 
            "valueToReturn"
        );

        // Display parameter information.
        ParameterInfo[] parameters = hello.GetParameters();
        Console.WriteLine("\r\nParameters: name, type, ParameterAttributes");
        foreach( ParameterInfo p in parameters )
        {
            Console.WriteLine("\t{0}, {1}, {2}", 
                p.Name, p.ParameterType, p.Attributes);
        }

        // Create a delegate that represents the dynamic method. This
        // action completes the method, and any further attempts to
        // change the method will cause an exception.
        HelloDelegate hi = 
            (HelloDelegate) hello.CreateDelegate(typeof(HelloDelegate));

        // Use the delegate to execute the dynamic method.
        Console.WriteLine("\r\nUse the delegate to execute the dynamic method:");
        int retval = hi("\r\nHello, World!", 42);
        Console.WriteLine("Invoking delegate hi(\"Hello, World!\", 42) returned: " + retval);

        // Execute it again, with different arguments.
        retval = hi("\r\nHi, Mom!", 5280);
        Console.WriteLine("Invoking delegate hi(\"Hi, Mom!\", 5280) returned: " + retval);

        Console.WriteLine("\r\nUse the Invoke method to execute the dynamic method:");
        // Create an array of arguments to use with the Invoke method.
        object[] invokeArgs = {"\r\nHello, World!", 42};
        // Invoke the dynamic method using the arguments. This is much
        // slower than using the delegate, because you must create an
        // array to contain the arguments, and value-type arguments
        // must be boxed.
        object objRet = hello.Invoke(null, BindingFlags.ExactBinding, null, invokeArgs, new CultureInfo("en-us"));
        Console.WriteLine("hello.Invoke returned: " + objRet);
    }
}

/* This code example produces the following output:

Method Attributes: PrivateScope, Public, Static

Calling convention: Standard

DeclaringType is always null for dynamic methods.

This method contains verifiable code. (InitLocals = True)

Module: CommonLanguageRuntimeLibrary

Name: Hello

ReflectedType is null.

Method has no return parameter.

Return type: System.Int32

The return type has no custom attributes.

ToString: Int32 Hello(System.String, Int32)

Parameters: name, type, ParameterAttributes
        message, System.String, In
        valueToReturn, System.Int32, In

Use the delegate to execute the dynamic method:

Hello, World!
Invoking delegate hi("Hello, World!", 42) returned: 42

Hi, Mom!
Invoking delegate hi("Hi, Mom!", 5280) returned: 5280

Use the Invoke method to execute the dynamic method:

Hello, World!
hello.Invoke returned: 42
 */
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值