string now = Eval"System.DateTime.Now().ToString()" as string在Biri的链接之后,我得到了以下代"/>

关于反射:如何动态评估C#表达式?

关于反射:如何动态评估C#表达式?

How can I evaluate a C# expression dynamically?

我想做相当于:

1
2
object result = Eval("1 + 3");
string now    = Eval("System.DateTime.Now().ToString()") as string

在Biri的链接之后,我得到了以下代码片段(已修改为删除过时的方法ICodeCompiler.CreateCompiler()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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;\
"
);

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

    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;

}

旧话题,但是考虑到这是在谷歌搜索时显示的第一个线程,这是一个更新的解决方案。

您可以使用Roslyn的新脚本API评估表达式。

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

1
var result = CSharpScript.EvaluateAsync("1 + 3").Result;

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

您还可以根据需要指定评估结果类型:

1
var now = CSharpScript.EvaluateAsync<string>("System.DateTime.Now.ToString()").Result;

要评估更多高级代码段,传递参数,提供引用,名称空间和其他内容,请查看上面链接的Wiki。


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

您可以这样写:

1
2
var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");

要么

1
2
3
4
5
6
7
8
9
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);

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


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

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

微软解决方案

  • C#CodeDom CodeProvider:

    • 请参阅LINQ过去如何工作以及此CodeProject文章
  • 罗斯林:

    • 参阅有关Rosly Emit API的文章和此StackOverflow答案
  • DataTable.Compute:

    • 在StackOverflow上查看此答案
  • Webbrowser.Document.InvokeScript

    • 看到这个StackOverflow问题
  • 数据绑定器
  • 脚本控制

    • 请参阅有关StackOverflow的答案以及此问题
  • 执行PowerShell:

    • 请参阅此CodeProject文章

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

  • 表达评估库:

    • 逃跑
    • 动态表情
    • 计算器
    • CodingSeb.ExpressionEvaluator
    • 评估表达网
  • JavaScript解释器

    • 金特
  • 执行真实的C#

    • CS脚本
  • 推出自己的语言构建工具包,例如:

    • 讽刺
    • 拼图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
using Microsoft.JScript;
using Microsoft.JScript.Vsa;
using Convert = Microsoft.JScript.Convert;

namespace System
{
    public class MathEvaluator : INeedEngine
    {
        private VsaEngine vsaEngine;

        public virtual String Evaluate(string expr)
        {
            var engine = (INeedEngine)this;
            var result = Eval.JScriptEvaluate(expr, engine.GetEngine());

            return Convert.ToString(result, true);
        }

        VsaEngine INeedEngine.GetEngine()
        {
            vsaEngine = vsaEngine ?? VsaEngine.CreateEngineWithType(this.GetType().TypeHandle);
            return vsaEngine;
        }

        void INeedEngine.SetEngine(VsaEngine engine)
        {
            vsaEngine = engine;
        }
    }
}

What are the performance implications of doing this?

我们使用基于上述内容的系统,其中每个C#脚本都编译为内存中的程序集,并在单独的AppDomain中执行。还没有缓存系统,因此脚本每次运行时都会重新编译。我已经进行了一些简单的测试,并且非常简单的" Hello World"脚本在我的计算机上编译了大约0.7秒,包括从磁盘加载脚本。 0.7秒对于脚本系统来说可以,但是对于响应用户输入可能太慢,在这种情况下,像Flee这样的专用解析器/编译器可能更好。

1
2
3
4
5
6
7
8
using System;
public class Test
{
    static public void DoStuff( Scripting.IJob Job)
    {
        Console.WriteLine("Heps" );
    }
}

虽然C#本机不支持Eval方法,但我有一个C#eval程序,它允许评估C#代码。它提供了在运行时评估C#代码的功能,并支持许多C#语句。实际上,此代码可在任何.NET项目中使用,但是仅限于使用C#语法。请查看我的网站http://csharp-eval.com,以获取更多详细信息。


看起来还有一种使用RegEx和XPathNavigator评估表达式的方法。我还没有机会对其进行测试,但是我有点喜欢它,因为它不需要在运行时编译代码或使用无法使用的库。

http://www.webtips.co.in/c/evaluate-function-in-c-net-as-eval-function-in-javascript.aspx

我会尝试一下,然后告诉它是否有效。我也打算在Silverlight中尝试它,但是为时已晚,现在我几乎睡着了。


推荐阅读