在运行时动态创建函数

时间:2009-07-03 16:23:30

标签: c# .net-3.5 delegates lambda

可能甚至不可能这样做,但无论如何我会问。 是否可以创建一个接收字符串的函数,然后将其用作lambda中使用的转到运算符(=>)的右侧参数?

实际上,我想要做的是能够在运行时重新定义特定类的特定方法。我希望在程序运行时写下一个函数并将其附加到委托。有可能吗?

8 个答案:

答案 0 :(得分:9)

你有几种方法可以做到:

答案 1 :(得分:8)

最简单的方法可能就是TcKs建议的DLINQ。

最快(我相信,在3.5中)是创建一个DynamicMethod。它也是最可怕的方法。你实际上是使用IL构建一个方法,它与用机器语言编写代码的感觉大致相同。

我需要这样做才能在某些事情上动态附加事件处理程序(好吧,我不需要这样做,我只是想让单元测试事件更容易)。当时看起来有点令人生畏,因为我不知道有关IL的废话,但我想出了一个简单的方法来实现这一点。

您所做的是创建一个完全符合您需要的方法。越紧凑越好。如果我能弄清楚你想要做什么,我会提供一个例子。您在DLL项目中的类中编写此方法,并在发布模式下编译它。然后在Reflector中打开DLL并反汇编您的方法。 Reflector为您提供了您希望反汇编的语言选项 - 选择IL。现在,您需要添加到动态方法中的确切调用。只需按照MSDN上的示例,为您反映的方法代码切换示例的IL。

动态方法一旦构造,就会以与编译方法大致相同的速度调用(看到一个测试,其中动态方法可以在约20ms内被调用,其中反射超过200ms)。

答案 2 :(得分:5)

您的问题很不清楚,但您当然可以使用表达式树在执行时动态创建委托。 (还有其他方法可以做到这一点,例如CodeDOM,但表达式树更容易,如果它们可以满足您的所有需求。但是,您可以做的事情存在很大的限制。)

虽然使用带有一些捕获变量的lambda表达式通常更容易。

例如,要创建一个将指定数量添加到任何整数的函数,您可以编写:

static Func<int, int> CreateAdder(int amountToAdd)
{
    return x => x + amountToAdd;
}

...
var adder = CreateAdder(10);
Console.WriteLine(adder(5)); // Prints 15

如果这没有帮助,请澄清您的问题。

答案 3 :(得分:3)

不是我推荐其他更好的选项,但是有一个7 th 方法,那就是使用AssemblyBuilder,{{1} ModuleBuilder命名空间中的},TypeBuilderMethodBuilder来创建动态程序集。这与使用System.Reflection.Emit的voodoo相同。

例如,您可以在运行时使用这些来为类型创建代理类并覆盖该类型的虚拟方法。

这里有一些代码......

DynamicMethod

答案 4 :(得分:0)

如果将方法声明为虚拟,则可以使用Castle的DynamicProxy替换动态生成的(使用其他答案的方法之一)在运行时实现:

  

Castle DynamicProxy是一个用于在运行时动态生成轻量级.NET代理的库。代理对象允许在不修改类的代码的情况下拦截对对象成员的调用。类和接口都可以代理,但只能拦截虚拟成员。

答案 5 :(得分:0)

你问题的第二段表明你真正想要的是直截了当IOC(控制倒置)

不是声明类的实例,而是声明接口的实例,并根据您选择的条件,使用特定的重写类及其中的正确方法。希望这是有道理的。

答案 6 :(得分:0)

您应首先检查您的问题是否可以通过简单的多态解决。除非您将抽象互操作性定义为另一种语言或编辑编译器,否则尝试在运行时更改方法可能是解决问题的错误方法。

答案 7 :(得分:0)

使用.net core 3.1,可以用IL语言创建动态方法(mono也一样):

using System.Linq.Expressions;
using System.Reflection.Emit;

class Program
{
    static void Main()
    {
        DynamicMethod hellomethod = new DynamicMethod("WriteLine", typeof(void), new[] { typeof(string) }, typeof(Program).Module);
        ILGenerator il = hellomethod.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
        il.Emit(OpCodes.Ret);
        Action<string> hello4 = (Action<string>)hellomethod.CreateDelegate(typeof(Action<string>));
        hello4("Hello World!");
    }
}