5

我需要知道是否有任何库可以让我在给定表示数学函数的某个字符串的x^2+x+1情况下生成一个 C# func这将代表所述功能。

4

5 回答 5

11

使用 FLEE(Fast Lightweight Expression Evaluator)已经有一段时间了,效果很好。他们的版本也为 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
于 2012-06-02T17:35:52.597 回答
4

看看Roslyn API。它将允许您在运行时编译字符串

于 2012-06-02T17:14:51.610 回答
2

您可以使用CSharpCodeProvider类将代码编译为文件/程序集并动态加载已编译的程序集。此处描述了如何从您的程序中使用编译器 。这个Stackoverflow 问题展示了如何加载已编译的程序集。请记住,您需要将函数包装在一个类中以便稍后加载和执行它。

或者,您可以使用CS-Script来完成脏程序集的编译、加载和执行工作。

于 2012-06-02T17:20:27.227 回答
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,当它在 RTM 中发布时也将使用Roslyn 。

于 2012-06-02T18:02:53.010 回答
0

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

于 2012-06-02T17:19:07.277 回答