هل من الممكن تجميع وتنفيذ القانون الجديد في وقت التشغيل في .الشبكة ؟

StackOverflow https://stackoverflow.com/questions/234217

  •  04-07-2019
  •  | 
  •  

سؤال

ملاحظة:التعبير الرياضي التقييم ليس التركيز على هذا السؤال.أريد تجميع وتنفيذ القانون الجديد في وقت التشغيل في .صافي. أن يقال...

أود أن تسمح للمستخدم إدخال أي المعادلة كما يلي في مربع النص:

x = x / 2 * 0.07914
x = x^2 / 5

و هذه المعادلة المطبقة على البيانات الواردة نقطة.البيانات الواردة نقاط هي ممثلة x و كل نقطة من نقاط البيانات تتم معالجتها من قبل المستخدم المحدد المعادلة.أنا فعلت هذا منذ سنوات, ولكن لم يعجبني الحل لأنه يتطلب تحليل النص من المعادلة لكل حساب:

float ApplyEquation (string equation, float dataPoint)
{
    // parse the equation string and figure out how to do the math
    // lots of messy code here...
}

عندما كنت تجهيز قوارب من نقاط البيانات ، وهذا يدخل قدرا كبيرا من النفقات العامة.وأود أن تكون قادرة على ترجمة المعادلة في وظيفة, على الطاير, بحيث كان من المفترض أن يكون تحليل مرة واحدة.سوف ننظر بشيء من هذا القبيل:

FunctionPointer foo = ConvertEquationToCode(equation);
....
x = foo(x);  // I could then apply the equation to my incoming data like this

وظيفة ConvertEquationToCode أن تحليل المعادلة والعودة مؤشر إلى الوظيفة التي تطبق الرياضيات المناسبة.

التطبيق سوف تكون أساسا كتابة رمز جديد في وقت التشغيل.هل هذا ممكن مع .الشبكة ؟

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

المحلول

نعم!باستخدام أساليب وجدت في مايكروسوفت.CSharp, النظام.CodeDom.مترجم, ، النظام.انعكاس اسم المساحات.هنا هو بسيط وحدة التحكم التطبيق الذي يجمع فئة ("SomeClass") مع أسلوب واحد ("Add42") ثم يسمح لك استدعاء هذا الأسلوب.هذا هو عارية العظام على سبيل المثال أن مهيأ وصولا إلى منع أشرطة التمرير من الظهور في عرض رمز.هو فقط لإثبات تجميع و استخدام القانون الجديد في وقت التشغيل.

using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Reflection;

namespace RuntimeCompilationTest {
    class Program
    {
        static void Main(string[] args) {
            string sourceCode = @"
                public class SomeClass {
                    public int Add42 (int parameter) {
                        return parameter += 42;
                    }
                }";
            var compParms = new CompilerParameters{
                GenerateExecutable = false, 
                GenerateInMemory = true
            };
            var csProvider = new CSharpCodeProvider();
            CompilerResults compilerResults = 
                csProvider.CompileAssemblyFromSource(compParms, sourceCode);
            object typeInstance = 
                compilerResults.CompiledAssembly.CreateInstance("SomeClass");
            MethodInfo mi = typeInstance.GetType().GetMethod("Add42");
            int methodOutput = 
                (int)mi.Invoke(typeInstance, new object[] { 1 }); 
            Console.WriteLine(methodOutput);
            Console.ReadLine();
        }
    }
}

نصائح أخرى

قد حاول هذا: Calculator.Net

فإنه سيتم تقييم التعبير الرياضيات.

من نشر هذا الدعم ما يلي:

MathEvaluator eval = new MathEvaluator();
//basic math
double result = eval.Evaluate("(2 + 1) * (1 + 2)");
//calling a function
result = eval.Evaluate("sqrt(4)");
//evaluate trigonometric 
result = eval.Evaluate("cos(pi * 45 / 180.0)");
//convert inches to feet
result = eval.Evaluate("12 [in->ft]");
//use variable
result = eval.Evaluate("answer * 10");
//add variable
eval.Variables.Add("x", 10);            
result = eval.Evaluate("x * 10");

تحميل الصفحة و وزعت بموجب ترخيص BSD.

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

هنا هو مقال (لم أكثر من منزوع الدسم ذلك) الذي ينبغي الحصول على أنك بدأته:

http://www.c-sharpcorner.com/UploadFile/ChrisBlake/RunTimeCompiler12052005045037AM/RunTimeCompiler.aspx

يمكنك أيضا إنشاء نظام.Xml.XPath.XPathNavigator من فارغ "دمية" أكس ستريم ، وتقييم التعبير باستخدام XPath المقيم:

static object Evaluate ( string xp )
{
  return _nav.Evaluate ( xp );
}
static readonly System.Xml.XPath.XPathNavigator _nav
  = new System.Xml.XPath.XPathDocument (
      new StringReader ( "<r/>" ) ).CreateNavigator ( );

إذا كنت ترغب في تسجيل المتغيرات تستخدم في هذا التعبير ، يمكنك بناء حيوي XML التي يمكن أن تمر في تقييم الزائد أن يأخذ XPathNodeIterator.

<context>
  <x>2.151</x>
  <y>231.2</y>
</context>

ثم يمكنك كتابة عبارات مثل "x / 2 * 0.07914" ثم x هو قيمة عقدة في XML السياق.شيء جيد آخر هو, سيكون لديك الوصول إلى جميع XPath الوظائف الأساسية ، والتي تشمل الرياضيات سلسلة أساليب التلاعب و المزيد من الأشياء.

إذا كنت تريد أن تأخذ أكثر من ذلك ، حتى يمكنك بناء الخاصة بك XsltCustomContext(أو سوء وظيفة هنا على الطلب) حيث يمكنك حل الإشارات إلى تمديد وظائف والمتغيرات:

object result = Evaluate ( "my:func(234) * $myvar" );

بلدي:وظائفها يتم تعيين إلى C#/.صافي الأسلوب الذي يأخذ مزدوجة أو الباحث كما المعلمة.myvar سجلت على أنها متغير داخل XSLT السياق.

يمكنك محاولة النظر في أي CodeDom أو التعبير امدا الأشجار.أعتقد أن أي واحد من هؤلاء أن تسمح لك لتحقيق ذلك.أشجار التعبير هي على الأرجح أفضل طريقة للذهاب ولكن أيضا لديها أعلى منحنى التعلم.

لقد فعلت هذا باستخدام CSharpCodeProvider من خلال خلق المرجل لوحة فئة وظيفة الأشياء كما const سلسلة داخل مولد الدرجة.ثم إدخال رمز المستخدم في المرجل لوحة تجميع.

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

إذا كان الأمن في كل قلق ، أود أن أوصي باستخدام التعبير امدا الأشجار, ولكن إذا لم, باستخدام CSharpCodeProvider هي قوية إلى حد ما الخيار.

يمكن أن تبدأ هنا وإذا كنت تريد حقا للوصول الى ذلك ، بو يمكن تعديلها لتلبية الاحتياجات الخاصة بك.يمكنك أيضا دمج LUA مع .صافي.أي ثلاثة من هذه يمكن استخدامها داخل الجسم من مندوب الخاص بك ConvertEquationToCode.

هل رأيت http://ncalc.codeplex.com ?

إنه الموسعة ، سريع (على سبيل المثاللديها ذاكرة التخزين المؤقت) تمكنك من توفير وظائف مخصصة و varaibles في وقت التشغيل عن طريق التعامل مع EvaluateFunction/EvaluateParameter الأحداث.مثال التعبيرات يمكن أن تحليل:

Expression e = new Expression("Round(Pow(Pi, 2) + Pow([Pi2], 2) + X, 2)"); 

  e.Parameters["Pi2"] = new Expression("Pi * Pi"); 
  e.Parameters["X"] = 10; 

  e.EvaluateParameter += delegate(string name, ParameterArgs args) 
    { 
      if (name == "Pi") 
      args.Result = 3.14; 
    }; 

  Debug.Assert(117.07 == e.Evaluate()); 

كما يعالج unicode & العديد من نوع البيانات أصلا.لأنه يأتي مع قرن الوعل الملف إذا كنت ترغب في تغيير القواعد.هناك أيضا شوكة التي تدعم MEF في تحميل وظائف جديدة.

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

إذا فشل كل شيء آخر ، هناك فئات بموجب النظام.انعكاس.تنبعث منها مساحة الاسم التي يمكنك استخدامها لإنتاج المجالس الجديدة, فصول, والأساليب.

يمكنك استخدام system.CodeDom توليد رمز وتجميع على الطاير نظرة هنا

يمكنك تنفيذ postfix كومة حاسبة.أساسا ما عليك القيام به هو تحويل تعبير إلى postfix التدوين, ثم ببساطة تكرار عبر الرموز في postfix لحساب.

هنا أكثر حداثة مكتبة تعبيرات بسيطة:النظام.Linq.ديناميكية.الأساسية.انها متوافقة مع .صافي القياسية/.صافي الأساسية متوفرة من خلال NuGet, و المصدر هو متاح.

https://system-linq-dynamic-core.azurewebsites.net/html/de47654c-7ae4-9302-3061-ea6307706cb8.htm https://github.com/StefH/System.Linq.Dynamic.Core https://www.nuget.org/packages/System.Linq.Dynamic.Core/

هذا هو خفيفة الوزن جدا و مكتبة ديناميكية.

كتبت المجمع بسيطة من الدرجة لهذه المكتبة التي دعونا لي أن تفعل أشياء من هذا القبيل:

  string sExpression = "(a == 0) ? 5 : 10";
  ExpressionEvaluator<int> exec = new ExpressionEvaluator<int>(sExpression);
  exec.AddParameter("a", 0);
  int n0 = exec.Invoke();

بمجرد التعبير هو ترجمة يمكنك ببساطة تحديث القيم المعلمة إعادة استدعاء التعبير.

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

أنا لا أعرف إذا كان من الممكن لتنفيذ ConvertEquationToCode وظيفة, ومع ذلك ، يمكنك إنشاء بنية البيانات التي تمثل الحساب تحتاج إلى تنفيذ.

على سبيل المثال ، يمكنك بناء شجرة الذي عقد ورقة تمثل مدخلات الحساب الخاص بك الذي غير ورقة العقد تمثل نتائج المتوسطة و التي عقدة الجذر يمثل كل حساب.

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top