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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/53844/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 10:08:01  来源:igfitidea点击:

How can I evaluate a C# expression dynamically?

提问by Daren Thomas

I would like to do the equivalent of:

我想做相当于:

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

Following Biri s link, I got this snippet (modified to remove obsolete method ICodeCompiler.CreateCompiler():

在 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;

}  

回答by JJJ

What are the performance implications of doing this?

这样做对性能有什么影响?

We use a system based on something like the above mentioned, where each C# script is compiled to an in-memory assembly and executed in a separate AppDomain. There's no caching system yet, so the scripts are recompiled every time they run. I've done some simple testing and a very simple "Hello World" script compiles in about 0.7 seconds on my machine, including loading the script from disk. 0.7 seconds is fine for a scripting system, but might be too slow for responding to user input, in that case a dedicated parser/compiler like Flee might be better.

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

using System;
public class Test
{
    static public void DoStuff( Scripting.IJob Job)
    {
        Console.WriteLine( "Heps" );
    }
}

回答by JJJ

Looks like there is also a way of doing it using RegEx and XPathNavigator to evaluate the expression. I did not have the chance to test it yet but I kind of liked it because it did not require to compile code at runtime or use libraries that could not be available.

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

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

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

I'll try it and tell later if it worked. I also intend to try it in Silverlight, but it is too late and I'm almost asleep to do it now.

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

回答by Rudolf_Abel

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;
        }
    }
}

回答by xnaterm

While C# doesn't have any support for an Eval method natively, I have a C# eval program that does allow for evaluating C# code. It provides for evaluating C# code at runtime and supports many C# statements. In fact, this code is usable within any .NET project, however, it is limited to using C# syntax. Have a look at my website, http://csharp-eval.com, for additional details.

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

回答by Davide Icardi

I have written an open source project, Dynamic Expresso, that can convert text expression written using a C# syntax into delegates (or expression tree). Text expressions are parsed and transformed into Expression Treeswithout using compilation or reflection.

我编写了一个开源项目Dynamic Expresso,它可以将使用 C# 语法编写的文本表达式转换为委托(或表达式树)。文本表达式在不使用编译或反射的情况下被解析并转换为表达式树

You can write something like:

你可以这样写:

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

or

或者

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);

My work is based on Scott Gu article http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx.

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

回答by Ridkuma

Old topic, but considering this is one of the first threads showing up when googling, here is an updated solution.

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

You can use Roslyn's new Scripting API to evaluate expressions.

您可以使用Roslyn 的新脚本 API 来计算表达式

If you are using NuGet, just add a dependency to Microsoft.CodeAnalysis.CSharp.Scripting. To evaluate the examples you provided, it is as simple as:

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

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

This obviously does not make use of the scripting engine's async capabilities.

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

You can also specify the evaluated result type as you intended:

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

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

To evaluate more advanced code snippets, pass parameters, provide references, namespaces and whatnot, check the wiki linked above.

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

回答by cdiggins

If you specifically want to call into code and assemblies in your own project I would advocate using the C# CodeDom CodeProvider.

如果您特别想在自己的项目中调用代码和程序集,我会提倡使用C# CodeDom CodeProvider

Here is a list of the most popular approaches that I am aware of for evaluating string expressions dynamically in C#.

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

Microsoft Solutions

微软解决方案

Non-Microsoft solutions (not that there is anything wrong with that)

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