是否有用于解析字符串以创建 C# 函数的工具

本文关键字:创建 函数 工具 字符串 用于 是否 | 更新日期: 2023-09-27 18:36:02

我需要知道是否有任何库允许我,给定一个表示数学函数的某个字符串,比如说,x^2+x+1,(不关心字符串格式如何,任何对我有用)生成一个表示所述函数的 C# func。

是否有用于解析字符串以创建 C# 函数的工具

使用 FLEE(快速轻量级表达式计算器)已经有一段时间了,它一直工作得很好。 他们有一个版本,也维护了Silverlight的大部分功能。 它旨在满足您的要求,甚至更多。

http://flee.codeplex.com/

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

从您的评论中给出您的示例来评估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

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

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

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

你可以使用 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。

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