如何动态评估C#表达式?

Dar*_*mas 49 c# reflection eval

我想做相当于:

object result = Eval("1 + 3");
string now    = Eval("System.DateTime.Now().ToString()") as string
Run Code Online (Sandbox Code Playgroud)

在Biri的链接之后,我得到了这个片段(修改后删除了过时的方法ICodeCompiler.CreateCompiler():

private object Eval(string sExpression)
{
    CSharpCodeProvider c = new CSharpCodeProvider();
    CompilerParameters cp = new CompilerParameters();

    cp.ReferencedAssemblies.Add("system.dll");

    cp.CompilerOptions = "/t:library";
    cp.GenerateInMemory = true;

    StringBuilder sb = new StringBuilder("");
    sb.Append("using System;\n");

    sb.Append("namespace CSCodeEvaler{ \n");
    sb.Append("public class CSCodeEvaler{ \n");
    sb.Append("public object EvalCode(){\n");
    sb.Append("return " + sExpression + "; \n");
    sb.Append("} \n");
    sb.Append("} \n");
    sb.Append("}\n");

    CompilerResults cr = c.CompileAssemblyFromSource(cp, sb.ToString());
    if (cr.Errors.Count > 0)
    {
        throw new InvalidExpressionException(
            string.Format("Error ({0}) evaluating: {1}", 
            cr.Errors[0].ErrorText, sExpression));
    }

    System.Reflection.Assembly a = cr.CompiledAssembly;
    object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler");

    Type t = o.GetType();
    MethodInfo mi = t.GetMethod("EvalCode");

    object s = mi.Invoke(o, null);
    return s;

}  
Run Code Online (Sandbox Code Playgroud)

小智 26

老话题,但考虑到这是谷歌搜索时出现的第一个线程之一,这是一个更新的解决方案.

您可以使用Roslyn的新Scripting API来计算表达式.

如果您正在使用NuGet,只需向Microsoft.CodeAnalysis.CSharp.Scripting添加依赖项.要评估您提供的示例,它很简单:

var result = CSharpScript.EvaluateAsync("1 + 3").Result;
Run Code Online (Sandbox Code Playgroud)

这显然没有利用脚本引擎的异步功能.

您还可以按预期指定评估结果类型:

var now = CSharpScript.EvaluateAsync<string>("System.DateTime.Now.ToString()").Result;
Run Code Online (Sandbox Code Playgroud)

要评估更高级的代码片段,传递参数,提供引用,命名空间等等,请检查上面链接的wiki.

  • 非常慢。增加了 30 秒来计算简单的三级 40 表达式 (2认同)
  • @hungryMind 你不只是从表面上使用“EvaluateAsync”。使用此方法时需要考虑 3 件事。1.罗斯林热身。2. 表达式编译。3.表达评估。前两个占用了您在此处看到的 40 秒的 99%。如果您缓存“CSharpScrip.Create”的结果并使用它,您将获得所请求字符串的本机性能。 (2认同)

Dav*_*rdi 25

我编写了一个开源项目Dynamic Expresso,它可以将使用C#语法编写的文本表达式转换为委托(或表达式树).解析文本表达式并将其转换为表达式树,而无需使用编译或反射.

你可以这样写:

var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");
Run Code Online (Sandbox Code Playgroud)

要么

var interpreter = new Interpreter()
                .SetVariable("service", new ServiceExample());

string expression = "x > 4 ? service.aMethod() : service.AnotherMethod()";

Lambda parsedExpression = interpreter.Parse(expression, 
                        new Parameter("x", typeof(int)));

parsedExpression.Invoke(5);
Run Code Online (Sandbox Code Playgroud)

我的工作基于Scott Gu的文章http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx.


cdi*_*ins 6

如果您特别想在自己的项目中调用代码和程序集,则建议使用C#CodeDom CodeProvider

这是我所知道的用于在C#中动态评估字符串表达式的最流行方法的列表。

微软解决方案

非Microsoft解决方案(不是说这有什么问题)