سؤال

هناك العديد من الخوارزميات لتقييم التعبيرات ، على سبيل المثال:

  1. من النسب العودية
  2. خوارزمية الساحة
  3. عكس تدوين البولندية

هل هناك أي طريقة لتقييم أي تعبير رياضي باستخدام C# .NET Reflection أو غيرها من تقنية .NET الحديثة؟

هل كانت مفيدة؟

المحلول

علاوة على إجابة Thomas ، من الممكن بالفعل الوصول إلى مكتبات JScript (التي تم إهمالها) مباشرة من C#، مما يعني أنه يمكنك استخدام ما يعادل JScript's 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.relection ؛

هذا هو الرمز:

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 });

استبدل "المعلمات" و "التعبير" بأي شيء ، وحصلت على مُقيِّم تعبير عام.

إذا حصلت على fileNotfoundException في results.compiledAssembly ، فإن المقتطف فشل في التجميع.

قد ترغب أيضًا في إلقاء نظرة على System.codedom.codesnippetexpression فئة. يتم استخدامه في قراءة التعبيرات بشكل أكثر تحديداً ، ولكن لا يمكن تجميع التعبير بمفرده ، لذلك ستحتاج إلى استخدام المزيد من الترميز لبناء فئة عاملة وطريقة من حولها. يعد هذا مفيدًا إذا كنت تريد أن تكون قادرًا على معالجة نوع الفصل الذي تنشئه برمجيًا. من الجيد إنشاء CODESNippetCompileUnit لإنشاء فئة عاملة كاملة في وقت واحد (وأبسط على سبيل المثال) ولكن للتلاعب بها ، يجب عليك القيام بمعالجة سلسلة غير مريحة.

على الرغم من أن استخدام خدمات برنامج التحويل البرمجي يعد حلاً بسيطًا وفعالًا ، إلا أنه يثير مشكلات أمان خطيرة إذا تم إدخال التعبير من قبل المستخدم ، لأنه يمكن أن ينفذ فعليًا اى شئ.

هناك حل آخر بسيط للغاية أكثر أمانًا: استفد من JScript Eval وظيفة. تحتاج فقط إلى اتباع هذه الخطوات:

إنشاء ملف JS يسمى JSMath.js:

class JsMath
{
    static function Eval(expression : String) : double
    {
        return eval(expression);
    };
}

قم بتجميعها في مكتبة الفصل:

jsc /t:library JsMath.js

الرجوع إلى مكتبة JSMath في مشروع C# الخاص بك ، واستخدمه على هذا النحو:

double result = JsMath.Eval(expression);

بالنسبة لي Vici.Parser يعمل بشكل جيد للغاية: تحقق من ذلك هنا ، إنه أكثر محللات التعبير مرونة وجدته حتى الآن.

(لقد استخدمناها لإعداد قواعد الأعمال "القابلة للقراءة البشرية" ، مع البيانات التي توفرها قاعدة بيانات SQL Server)

تتوفر أمثلة وهناك دعم جيد للغاية من قبل المطور (تحقق من منتدى الموقع).

ncalc هو الأفضل. يمكنك العثور عليه في codeplex أيضا في الكتلة.
NCALC هو تقييم تعبيرات رياضية في .NET. يمكن لـ NCALC تحليل أي تعبير وتقييم النتيجة ، بما في ذلك المعلمات الثابتة أو الديناميكية والوظائف المخصصة.

أعتقد أن هذه هي أفضل طريقة للجميع. إجابة Petar Repac رائع. استخدام وسيطة "التعبير" لكائن DataColumn يحل الموضوع بشكل لا يصدق وسهولة:

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"]);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top