【问题标题】:from string to method从字符串到方法
【发布时间】:2026-02-04 02:45:01
【问题描述】:

简短的问题, .NET 4.0 中是否有办法获取表示方法体的字符串,并将其编译为 Func/Action,或者是否有库可以这样做?

澄清:

我需要一些不会生成任何 dll 的东西,它必须是完全动态的,比如 javascript 中的 eval()。我需要在不创建 dll 的情况下将字符串转换为 Func/Action。

【问题讨论】:

  • 你的意思是 JavaScript 用 eval() 做的事情?
  • 您在寻找运行时或设计时解决方案吗?如果是后者,您总是可以使用像 MyGeneration 或 T4 这样的代码生成模板吗?如果是前者,您是否查看过 Microsoft.CSharp 和 System.CodeCom.Compiler 命名空间?

标签: c# delegates expression-trees


【解决方案1】:

您可以使用CSharpCodeProvider class 将源代码编译成程序集。

例如:

var compiler = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
var options = new CompilerParameters { OutputAssembly = path);
var results = compiler.CompileAssemblyFromFile(options, sourceFile);

要编译单个函数,您可以使用适当的using 语句将其包装在一个类中以创建完整的源文件,然后使用反射获取委托:

var assembly = results.CompiledAssembly;
var method = assembly.GetType("WrapperClassName").GetMethod("MethodName");
var delegate = (Action)Delegate.CreateDelegate(typeof(Action), method);

对于more complete example

static readonly Assembly[] References = new[] { typeof(Enumerable).Assembly, typeof(Component).Assembly };
public Action CompileMethodstring source) {
    var options = new CompilerParameters(References.Select(a => a.Location).ToArray()) {
        GenerateInMemory = true
    };
    string fullSource = @"public static class HolderClass { public static void Execute() { \r\n" + source + "\r\n} }";
    try {
        var compiler = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });

        var results = compiler.CompileAssemblyFromSource(options, fullSource);

        if (results.Errors.Count > 0)
            throw new InvalidOperationException(String.Join(
                Environment.NewLine, 
                results.Errors.Cast<CompilerError>().Select(ce => ce.ErrorText)
            ));

        return (Action)Delegate.CreateDelegate(
            typeof(Action),
            results.CompiledAssembly.GetType("HolderClass").GetMethod("Execute")
        );
    } finally { options.TempFiles.Delete(); }
}

【讨论】:

  • 其实,这可能行得通,我只需要生成一点代码。
【解决方案2】:

您也可以使用CS-Script.Net 这是一个嵌入式脚本平台,您也可以执行以下操作:

dynamic script = CSScript.LoadCode(@"using System;
                                     public class Script
                                     {
                                         public void SayHello(string greeting)
                                         {
                                             Console.WriteLine(greeting);
                                         }
                                     }")
                                    .CreateObject("*");
script.SayHello("Hello World!");

我已经在生产环境中使用了将近 2 年,它是创建可配置应用程序的好方法。如果你有兴趣,我有一个sample project

【讨论】:

  • 这看起来很有希望。你知道它是否适用于中等信任度?
  • 据我所知,是的。这是它支持的脚本模型的链接:csscript.net/help/Type_sharing_patern.html。项目负责人 Oleg 反应迅速,如有其他问题,您可以随时与他联系。
【解决方案3】:

CSharpCodeProvider 可能是您正在寻找的。但是,您需要创建有效的 C# 代码(也就是说,您需要为该方法创建一个类)。

【讨论】: