如何动态计算 C# 表达式?

发布于 2024-07-05 03:41:59 字数 1458 浏览 7 评论 0原文

我想做相当于:

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

按照 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;

}  

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():

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;

}  

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

温柔一刀 2024-07-12 03:41:59

我刚刚用纯 C# 编写了一个类似的库 (Matheval)。
它允许像 Excel 公式一样评估字符串和数字表达式。

using System;
using org.matheval;
                    
public class Program
{
    public static void Main()
    {
        Expression expression = new Expression("IF(time>8, (HOUR_SALARY*8) + (HOUR_SALARY*1.25*(time-8)), HOUR_SALARY*time)");
        //bind variable
        expression.Bind("HOUR_SALARY", 10);
        expression.Bind("time", 9);
        //eval
        Decimal salary = expression.Eval<Decimal>();    
        Console.WriteLine(salary);
    }
}

I have just written a similar library (Matheval) in pure C#.
It allows evaluating string and number expression like excel fomular.

using System;
using org.matheval;
                    
public class Program
{
    public static void Main()
    {
        Expression expression = new Expression("IF(time>8, (HOUR_SALARY*8) + (HOUR_SALARY*1.25*(time-8)), HOUR_SALARY*time)");
        //bind variable
        expression.Bind("HOUR_SALARY", 10);
        expression.Bind("time", 9);
        //eval
        Decimal salary = expression.Eval<Decimal>();    
        Console.WriteLine(salary);
    }
}
一指流沙 2024-07-12 03:41:59

这样做会对性能产生什么影响?

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

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

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.

using System;
public class Test
{
    static public void DoStuff( Scripting.IJob Job)
    {
        Console.WriteLine( "Heps" );
    }
}
灼疼热情 2024-07-12 03:41:59

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

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

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

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.

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.

╰つ倒转 2024-07-12 03:41:59

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

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.

情徒 2024-07-12 03:41:59

这里有一段很好的代码
https://www.c -sharpcorner.com/article/codedom-calculator-evaluating-c-sharp-math-expressions-dynamica/

下载这个并将其作为一个可以在您的项目中引用的类库。 这似乎非常快速和简单

也许这可以帮助!

There is a nice piece of code here
https://www.c-sharpcorner.com/article/codedom-calculator-evaluating-c-sharp-math-expressions-dynamica/

Download this and make it a class library which may be referenced in your project. This seems to be pretty fast and simple

Perhaps this could help !

浅浅淡淡 2024-07-12 03:41:59

只需使用连接字符串将算术表达式传递给 sql

// INPUT
string eval = "SELECT ((1+2)-3*4)/5.0";

string strCon = $"Server=.\sqlexpress; Database=master; integrated security = true";

SqlConnection sqlCon = new SqlConnection(strCon);
sqlCon.Open();

SqlCommand cmd = new SqlCommand(eval, sqlCon);

SqlDataAdapter da = new SqlDataAdapter(cmd);
string result = da.SelectCommand.ExecuteScalar().ToString();

// OUTPUT
Console.WriteLine(result);

您必须添加
使用 System.Data.SqlClient;

Just pass your aritmetic expression to sql using a conection string

// INPUT
string eval = "SELECT ((1+2)-3*4)/5.0";

string strCon = 
quot;Server=.\sqlexpress; Database=master; integrated security = true";

SqlConnection sqlCon = new SqlConnection(strCon);
sqlCon.Open();

SqlCommand cmd = new SqlCommand(eval, sqlCon);

SqlDataAdapter da = new SqlDataAdapter(cmd);
string result = da.SelectCommand.ExecuteScalar().ToString();

// OUTPUT
Console.WriteLine(result);

You must add
using System.Data.SqlClient;

方圜几里 2024-07-12 03:41:59
    static double EvaluateExpression(string expression)
    {
        DataTable table = new DataTable();
        table.Columns.Add("expression", typeof(string), expression);
        DataRow row = table.NewRow();
        table.Rows.Add(row);
        return double.Parse((string)row["expression"]);
    }

MessageBox.Show( EvaluateExpression("((15.3 * 0.15) / 100 ) * 0.005 + (8500 * 0.754878)").ToString() );

结果:6416.46311475

    static double EvaluateExpression(string expression)
    {
        DataTable table = new DataTable();
        table.Columns.Add("expression", typeof(string), expression);
        DataRow row = table.NewRow();
        table.Rows.Add(row);
        return double.Parse((string)row["expression"]);
    }

MessageBox.Show( EvaluateExpression("((15.3 * 0.15) / 100 ) * 0.005 + (8500 * 0.754878)").ToString() );

Result : 6416.46311475

笨死的猪 2024-07-12 03:41:59
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;
        }
    }
}
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;
        }
    }
}
べ映画 2024-07-12 03:41:59

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

您可以这样写:

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

或者

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

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 Trees without using compilation or reflection.

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 .

过去的过去 2024-07-12 03:41:59

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

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

Microsoft 解决方案

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

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

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

Microsoft Solutions

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

瑶笙 2024-07-12 03:41:59

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

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

如果您使用 NuGet,只需添加对 Microsoft.CodeAnalysis.CSharp 的依赖项。脚本编写
要评估您提供的示例,很简单:

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

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

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

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

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

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.

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:

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文