数式を評価するための最良かつ最短の方法
-
08-07-2019 - |
質問
式を評価するためのアルゴリズムは多数あります。例:
C#.netリフレクションまたはその他の最新の.netテクノロジーを使用して数式を評価する方法はありますか?
解決
Thomasの答えに加えて、実際には、C#から(非推奨の)JScriptライブラリに直接アクセスできます。つまり、JScriptの eval
関数と同等のものを使用できます。
using Microsoft.JScript; // needs a reference to Microsoft.JScript.dll
using Microsoft.JScript.Vsa; // needs a reference to Microsoft.Vsa.dll
// ...
string expr = "7 + (5 * 4)";
Console.WriteLine(JScriptEval(expr)); // displays 27
// ...
public static double JScriptEval(string expr)
{
// error checking etc removed for brevity
return double.Parse(Eval.JScriptEvaluate(expr, _engine).ToString());
}
private static readonly VsaEngine _engine = VsaEngine.CreateEngine();
他のヒント
それは確かに可能です。 CodeSnippetCompileUnit クラスは基本的にこれを行います。 使用例のコードをいくつか書きました。これらの名前空間を含める必要があります。
- System.CodeDom.Compiler;
- System.CodeDom;
- Microsoft.CSharp;
- System.Reflection;
コードは次のとおりです。
string source = @"
class MyType
{
public static int Evaluate(<!parameters!>)
{
return <!expression!>;
}
}
";
string parameters = "int a, int b, int c";
string expression = "a + b * c";
string finalSource = source.Replace("<!parameters!>", parameters).Replace("<!expression!>", expression);
CodeSnippetCompileUnit compileUnit = new CodeSnippetCompileUnit(finalSource);
CodeDomProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
CompilerResults results = provider.CompileAssemblyFromDom(parameters, compileUnit);
Type type = results.CompiledAssembly.GetType("MyType");
MethodInfo method = type.GetMethod("Evaluate");
// The first parameter is the instance to invoke the method on. Because our Evaluate method is static, we pass null.
int result = (int)method.Invoke(null, new object[] { 4, -3, 2 });
'parameters'と 'expression'を何でも置き換えてください。そうすれば、一般的な式エバリュエーターになります。
results.CompiledAssemblyでFileNotFoundExceptionが発生した場合、スニペットはコンパイルに失敗しました。
System.CodeDom.CodeSnippetExpressionクラスも参照してください。式をより具体的に読み取るために使用されますが、式自体はコンパイルできないため、より多くのCodeDomを使用して作業クラスとメソッドを構築する必要があります。これは、生成するクラスの種類をプログラムで操作できるようにする場合に便利です。 CodeSnippetCompileUnitは、作業クラス全体を一度に生成するのに便利ですが(例ではより簡単です)、操作するには不便な文字列操作を行う必要があります。
コンパイラサービスの使用はシンプルで効率的なソリューションですが、ユーザーが式を入力すると、実質的に anything を実行する可能性があるため、深刻なセキュリティ問題が発生します。
さらに安全な非常に簡単なソリューションがもう1つあります。JScript Eval
関数を利用してください。次の手順に従う必要があります。
JsMath.jsという名前のjsファイルを作成します:
class JsMath
{
static function Eval(expression : String) : double
{
return eval(expression);
};
}
クラスライブラリにコンパイルします:
jsc /t:library JsMath.js
C#プロジェクトでJsMathライブラリを参照し、次のように使用します。
double result = JsMath.Eval(expression);
私にとってVici.Parserは非常にうまく機能します:ここでチェック、これまでに見つけた中で最も柔軟な式パーサー。
(SQLサーバーデータベースによって提供されるデータを使用して、「人間が読み取れる」ビジネスルールを設定するために使用しました)
サンプルが利用可能であり、開発者による非常に優れたサポートがあります(ウェブサイトのフォーラムを確認してください)。
これがすべての最善の方法だと思います。 Petar Repacの回答は素晴らしいです。 DataColumnオブジェクトの 'expression'引数を使用すると、信じられないほど簡単にトピックを解決できます。
static double Evaluate(string expression)
{
var loDataTable = new DataTable();
var loDataColumn = new DataColumn("Eval", typeof(double), expression);
loDataTable.Columns.Add(loDataColumn);
loDataTable.Rows.Add(0);
return (double)(loDataTable.Rows[0]["Eval"]);
}