たとえば、数学関数を表す特定の文字列が与えられた場合x^2+x+1
、(文字列形式がどのように機能するかは気にしないでください。どれでも機能します) C# func を生成できるライブラリがあるかどうかを知る必要があります。それはその機能を表します。
5 に答える
FLEE (Fast Lightweight Expression Evaluator) をしばらく使用していますが、うまく機能しています。Silverlight のほとんどの機能を維持するバージョンもあります。それは、あなたが求めていることをほぼ正確に実行するように設計されています。
Flee は、.NET フレームワーク用の式パーサーおよびエバリュエーターです。実行時に sqrt(a^2 + b^2) などの文字列式の値を計算できます。カスタム コンパイラ、厳密に型指定された式言語、および軽量の codegen を使用して、式を直接 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
RoslynAPIを見てください。実行時に文字列をコンパイルできるようになります
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 });
RTM でリリースされるときにもRoslynを使用する、より流暢なインターフェイス API を CodePlex でリリースする必要があります。