有没有一个工具可以将字符串解析成C#函数?

5

我需要知道是否有任何库可以让我根据表示数学函数的某个字符串(例如,x^2+x+1)生成一个代表该函数的 C# 函数(不关心字符串格式,任何格式都可以)。


1
你是在说类似于 C# 中的 eval 函数吗?https://dev59.com/pXVD5IYBdhLWcg3wWaVh http://www.codeproject.com/Articles/11939/Evaluate-C-Code-Eval-Function - Tim S.
不,我说的是一个库,例如接受字符串:x^2+x+1,并生成一个C#函数,给定X后相应地进行评估。 - user1432653
我的意思是将数学函数解析为C#中的函数。 - user1432653
5个回答

11

我已经使用FLEE(快速轻便表达式评估器)一段时间了,它一直表现出色。他们还提供了一个版本用于Silverlight保留大部分功能。它的设计几乎完全符合你所要求的,并且还可以做更多。

http://flee.codeplex.com/

Flee是.NET框架的表达式解析器和评估器。它允许您在运行时计算字符串表达式的值,例如sqrt(a^2+b^2)。它使用自定义编译器、强类型表达式语言和轻量级代码生成来直接编译表达式为IL。这意味着表达式评估非常快速和高效。

给定您在评论中的示例x^2+x+1(在记事本中编写):

public Func<double, double> CreateExpressionForX(string expression)
{

    ExpressionContext context = new ExpressionContext();
    // Define some variables
    context.Variables["x"] = 0.0d;

    // Use the variables in the expression
    IDynamicExpression e = context.CompileDynamic(expression);


    Func<double, double> expressionEvaluator = (double input) =>
    {
        content.Variables["x"] = input;
        var result = (double)e.Evaluate();
        return result;
    }

    return expressionEvaluator;
}



Func<double, double> expression = CreateExpressionForX("x^2 + x + 1");

double result1 = expression(1); //3
double result2 = expression(20.5); //441.75
double result3 = expression(-10.5); //121.75

Func<double, double> expression2 = CreateExpressionForX("3 * x + 10");

double result4 = expression2(1); //13
double result5 = expression2(20.5); //71.5
double result6 = expression2(-10.5); //-21.5

4

可以看一下Roslyn API,它能够让你在运行时编译字符串。


不错,尽管据我所知它还远未能真正运作/完成。看到整个概念如何与我们所有人使用C#/VB.NET的方式集成将会很有趣。 - YavgenyP

2
您可以使用CSharpCodeProvider类将代码编译为文件/程序集,并动态加载已编译的程序集。如何从您的程序中使用编译器,请参见此处。这个Stackoverflow问题演示了如何加载已编译的程序集。请注意,您需要将函数包装在一个类中,以便稍后加载和执行它。
或者您可以使用CS-Script来完成繁琐的程序集编译、加载和执行工作。

我的意思是将数学函数解析为C#中的函数。 - user1432653
你本来可以在你的原始问题中提到这一点。这个问题仍然可以通过表达式树很容易地解决,但我猜Chris Sinclair提供的工具也能很好地完成工作。 - YavgenyP

1

您可以使用CodeDOM来动态编译类型,关于此,在这里您可以找到一个流畅的接口来简化代码编写,例如:

var compileUnit = new FluentCodeCompileUnit()
    .Namespace("Sample1")
                .Class("Program")
                    .Method(MemberAttributes.Public | MemberAttributes.Static, "Main").Parameter(typeof(string[]), "args")
                        .CallStatic(typeof(Console), "WriteLine", Expr.Primitive("Hello Fluent CodeDom"))
                    .EndMethod

                    .Method(MemberAttributes.Public | MemberAttributes.Static, "Linq2CodeDomSupport").Parameter(typeof(string[]), "args")
                        .Stmt(ExprLinq.Expr(() => Console.WriteLine("Hello Linq2CodeDOM")))
                        .Declare(typeof(int), "random", ExprLinq.Expr(() => new Random().Next(10)))
                        .If((int random) => random <= 5)
                            .Stmt(ExprLinq.Expr(() => Console.WriteLine("Smaller or equal to 5.")))
                        .Else
                            .Stmt(ExprLinq.Expr(() => Console.WriteLine("Bigger than 5.")))
                        .EndIf
                    .EndMethod
               .EndClass
            .EndNamespace
        .EndFluent();

        var assembly = Helper.CodeDomHelper.CompileInMemory(compileUnit);
        assembly.GetType("Sample1.Program").GetMethod("Main").Invoke(null, new object[] { null });

我需要在CodePlex上发布一个更好的流畅接口API,它将在Roslyn发布RTM时使用。


0

看起来是一个不错的解决方案。当然,也可以使用表达式树和从字符串到表达式的解析来解决,后者可以在运行时编译并执行。


我的意思是将数学函数解析为C#中的函数。 - user1432653

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接