मैं गतिशील रूप से C # कोड का मूल्यांकन कैसे कर सकता हूं?


92

मैं eval("something()");जावास्क्रिप्ट में कोड को गतिशील रूप से निष्पादित करने के लिए कर सकता हूं । क्या मेरे लिए C # में एक ही काम करने का कोई तरीका है?

मैं जो करने की कोशिश कर रहा हूं उसका एक उदाहरण है: मेरे पास एक पूर्णांक चर (कहना i) है और मेरे पास कई गुण हैं: "संपत्ति 1", "संपत्ति 2", "संपत्ति 3", आदि। अब, मैं कुछ ऑपरेशन करना चाहता हूं "संपत्ति मैं " संपत्ति के मूल्य के आधार पर i

यह जावास्क्रिप्ट के साथ वास्तव में सरल है। क्या C # के साथ ऐसा करने का कोई तरीका है?



2
c # लौहभंडार का उभार। मैंने इसे c # 4.0 में आज़माया। सी # 2.0 के साथ कोई अनुभव नहीं
पीटर लॉन्ग

@ पैटर लोंग, मुझे आयरनपायथॉन के निष्कासन के लिए दस्तावेज कहां मिल सकते हैं?
स्मार्टकेवमैन

@ AdhipGupta मुझे पता है कि यह क्यू एंड ए बहुत दिनांकित है, लेकिन मैंने अभी-अभी एक वीडियो प्लेलिस्ट जारी की है जो डेविड इकार्डी के उत्तर में दिए गए विवरण की तरह है। यह नाटकीय रूप से अलग है, और शायद बाहर की जाँच के लायक है।
रिक रिग्स

जवाबों:


49

दुर्भाग्य से, C # उस तरह की गतिशील भाषा नहीं है।

हालाँकि, आप क्या कर सकते हैं, एक C # स्रोत कोड फ़ाइल बना सकते हैं, जो कक्षा और सब कुछ के साथ भरी हुई है, और इसे C # के लिए कोडडॉम प्रदाता के माध्यम से चलाएं और इसे एक असेंबली में संकलित करें, और फिर इसे निष्पादित करें।

MSDN पर इस फ़ोरम पोस्ट में पृष्ठ के नीचे कुछ उदाहरण कोड के साथ एक उत्तर होता है:
एक स्ट्रिंग से एक अनाम विधि बनाएं?

मैं शायद ही कहूंगा कि यह एक बहुत अच्छा समाधान है, लेकिन यह वैसे भी संभव है।

उस तार में आप किस तरह के कोड की उम्मीद करने जा रहे हैं? यदि यह वैध कोड का एक छोटा उपसमूह है, उदाहरण के लिए सिर्फ गणित के भाव, तो यह हो सकता है कि अन्य विकल्प मौजूद हों।


संपादित करें : ठीक है, जो मुझे पहले प्रश्नों को अच्छी तरह से पढ़ना सिखाता है। हाँ, परावर्तन आपको यहाँ कुछ मदद दे सकेगा।

यदि आप स्ट्रिंग को विभाजित करते हैं; सबसे पहले, व्यक्तिगत गुण प्राप्त करने के लिए, आप किसी वर्ग के लिए किसी विशेष संपत्ति के लिए एक संपत्ति संपत्ति प्राप्त करने के लिए निम्नलिखित कोड का उपयोग कर सकते हैं, और फिर उस वस्तु का उपयोग किसी विशेष वस्तु में हेरफेर करने के लिए कर सकते हैं।

String propName = "Text";
PropertyInfo pi = someObject.GetType().GetProperty(propName);
pi.SetValue(someObject, "New Value", new Object[0]);

लिंक: PropertyInfo.SetValue विधि


क्या होगा अगर गेटप्रॉपर्टी को x, y params के साथ एक फंक्शन होना चाहिए?, मतलब टेक्स्ट (1,2)?
user1735921

@ user1735921 फिर आपको GetMethod(methodName)इसके बजाय उपयोग करने की आवश्यकता होगी , पैरामीटर मानों को पार्स करें, और प्रतिबिंब का उपयोग करके विधि को कॉल करें।
लासे वी। कार्लसन जू

typeof (ObjectType) someObject.GetType ()
Thiago

32

रोसलिन स्क्रिप्टिंग एपीआई (अधिक नमूने यहां ) का उपयोग करते हुए :

// add NuGet package 'Microsoft.CodeAnalysis.Scripting'
using Microsoft.CodeAnalysis.CSharp.Scripting;

await CSharpScript.EvaluateAsync("System.Math.Pow(2, 4)") // returns 16

आप कोई भी कोड चला सकते हैं:

var script = await CSharpScript.RunAsync(@"
                class MyClass
                { 
                    public void Print() => System.Console.WriteLine(1);
                }")

और पिछले रनों में उत्पन्न कोड का संदर्भ दें:

await script.ContinueWithAsync("new MyClass().Print();");

14

ज़रुरी नहीं। आप जो चाहते हैं उसे प्राप्त करने के लिए प्रतिबिंब का उपयोग कर सकते हैं, लेकिन यह जावास्क्रिप्ट में लगभग उतना सरल नहीं होगा। उदाहरण के लिए, यदि आप किसी वस्तु के निजी क्षेत्र को किसी चीज़ में सेट करना चाहते हैं, तो आप इस फ़ंक्शन का उपयोग कर सकते हैं:

protected static void SetField(object o, string fieldName, object value)
{
   FieldInfo field = o.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
   field.SetValue(o, value);
}

11

यह c # के तहत एक eval फंक्शन है। मैंने इसका उपयोग अनाम कार्यों (लैम्ब्डा एक्सप्रेशंस) को एक स्ट्रिंग से परिवर्तित करने के लिए किया था। स्रोत: http://www.codeproject.com/KB/cs/evalcscode.aspx

public static object Eval(string sCSCode) {

  CSharpCodeProvider c = new CSharpCodeProvider();
  ICodeCompiler icc = c.CreateCompiler();
  CompilerParameters cp = new CompilerParameters();

  cp.ReferencedAssemblies.Add("system.dll");
  cp.ReferencedAssemblies.Add("system.xml.dll");
  cp.ReferencedAssemblies.Add("system.data.dll");
  cp.ReferencedAssemblies.Add("system.windows.forms.dll");
  cp.ReferencedAssemblies.Add("system.drawing.dll");

  cp.CompilerOptions = "/t:library";
  cp.GenerateInMemory = true;

  StringBuilder sb = new StringBuilder("");
  sb.Append("using System;\n" );
  sb.Append("using System.Xml;\n");
  sb.Append("using System.Data;\n");
  sb.Append("using System.Data.SqlClient;\n");
  sb.Append("using System.Windows.Forms;\n");
  sb.Append("using System.Drawing;\n");

  sb.Append("namespace CSCodeEvaler{ \n");
  sb.Append("public class CSCodeEvaler{ \n");
  sb.Append("public object EvalCode(){\n");
  sb.Append("return "+sCSCode+"; \n");
  sb.Append("} \n");
  sb.Append("} \n");
  sb.Append("}\n");

  CompilerResults cr = icc.CompileAssemblyFromSource(cp, sb.ToString());
  if( cr.Errors.Count > 0 ){
      MessageBox.Show("ERROR: " + cr.Errors[0].ErrorText, 
         "Error evaluating cs code", MessageBoxButtons.OK, 
         MessageBoxIcon.Error );
      return null;
  }

  System.Reflection.Assembly a = cr.CompiledAssembly;
  object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler");

  Type t = o.GetType();
  MethodInfo mi = t.GetMethod("EvalCode");

  object s = mi.Invoke(o, null);
  return s;

}

1
@ हशे वूप्स, मैंने टाइपो (लैम्बडा => लैम्ब्डा) को सही किया। मुझे नहीं पता था कि गीत को लमबाड़ा कहा जाता है इसलिए यह एक अनजाने में था। ;)
लार्गो

मैं समझ नहीं पा रहा था कि इस जवाब को कम वोट क्यों मिले। बहुत काम का है।
मुजफ्फर

9

मैंने एक ओपन सोर्स प्रोजेक्ट डायनेमिक एक्सप्रेसो लिखा है, जो C # सिंटैक्स को डेलिगेट्स (या एक्सप्रेशन ट्री) में लिखी गई टेक्स्ट एक्सप्रेशन को कन्वर्ट कर सकता है। अभिव्यक्तियों को संकलित किया जाता है और संकलन या प्रतिबिंब का उपयोग किए बिना अभिव्यक्ति पेड़ों में बदल दिया जाता है।

आप कुछ इस तरह लिख सकते हैं:

var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");

या

var interpreter = new Interpreter()
                      .SetVariable("service", new ServiceExample());

string expression = "x > 4 ? service.SomeMethod() : service.AnotherMethod()";

Lambda parsedExpression = interpreter.Parse(expression, 
                          new Parameter("x", typeof(int)));

parsedExpression.Invoke(5);

मेरा काम स्कॉट गु लेख http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx पर आधारित है ।


7

वह सब निश्चित रूप से काम करेगा। व्यक्तिगत रूप से, उस विशेष समस्या के लिए, मैं शायद थोड़ा अलग तरीका अपनाऊंगा। शायद कुछ इस तरह:

class MyClass {
  public Point point1, point2, point3;

  private Point[] points;

  public MyClass() {
    //...
    this.points = new Point[] {point1, point2, point3};
  }

  public void DoSomethingWith(int i) {
    Point target = this.points[i+1];
    // do stuff to target
  }
}

इस तरह के पैटर्न का उपयोग करते समय, आपको सावधान रहना होगा कि आपका डेटा संदर्भ द्वारा संग्रहीत किया गया है और मूल्य से नहीं। दूसरे शब्दों में, आदिम के साथ ऐसा मत करो। आपको उनके बड़े फूला हुआ वर्ग समकक्षों का उपयोग करना होगा।

मुझे एहसास हुआ कि यह बिल्कुल सवाल नहीं है, लेकिन सवाल का बहुत अच्छी तरह से जवाब दिया गया है और मुझे लगा कि शायद एक वैकल्पिक दृष्टिकोण मदद कर सकता है।


5

यदि आप C # कथनों को निष्पादित करना चाहते हैं, तो मैं अभी नहीं करता, लेकिन आप पहले से ही C # 2.0 में जावास्क्रिप्ट कथनों को निष्पादित कर सकते हैं। ओपन-सोर्स लाइब्रेरी जिंट इसे करने में सक्षम है। यह .NET के लिए एक जावास्क्रिप्ट दुभाषिया है। एक जावास्क्रिप्ट प्रोग्राम पास करें और यह आपके एप्लिकेशन के अंदर चलेगा। आप तर्क के रूप में C # ऑब्जेक्ट भी पास कर सकते हैं और उस पर स्वचालन कर सकते हैं।

इसके अलावा, अगर आप सिर्फ अपने गुणों पर अभिव्यक्ति का मूल्यांकन करना चाहते हैं, तो NCalc को आज़माएं


3

आप संपत्ति प्राप्त करने के लिए प्रतिबिंब का उपयोग कर सकते हैं और इसे लागू कर सकते हैं। कुछ इस तरह:

object result = theObject.GetType().GetProperty("Property" + i).GetValue(theObject, null);

अर्थात्, जिस वस्तु के पास संपत्ति है उसे "TheObject" कहा जाता है:


2

आप एक Webbrowser भी कार्यान्वित कर सकते हैं, फिर एक html-फ़ाइल लोड करें जिसमें जावास्क्रिप्ट शामिल हो।

फिर यू document.InvokeScriptइस ब्राउजर पर मेथड के लिए जाएं । Eval फ़ंक्शन का रिटर्न मान पकड़ा जा सकता है और आपकी ज़रूरत के सभी चीज़ों में परिवर्तित हो सकता है।

मैंने कई प्रोजेक्ट्स में ऐसा किया है और यह पूरी तरह से काम करता है।

आशा करता हूँ की ये काम करेगा


0

आप इसे एक प्रोटोटाइप फ़ंक्शन के साथ कर सकते हैं:

void something(int i, string P1) {
    something(i, P1, String.Empty);
}

void something(int i, string P1, string P2) {
    something(i, P1, P2, String.Empty);
}

void something(int i, string P1, string P2, string P3) {
    something(i, P1, P2, P3, String.Empty);
}

और इसी तरह...


0

पार्स करने के लिए प्रतिबिंब का उपयोग करता है और रन टाइम में किसी ऑब्जेक्ट के खिलाफ डेटा-बाइंडिंग अभिव्यक्ति का मूल्यांकन करता है।

DataBinder.Eval विधि


0

कोड को गतिशील रूप से संकलित करने और निष्पादित करने के कार्य को सरल बनाने के लिए मैंने एक पैकेज SharpByte.Dynamic लिखा है । कोड को विस्तार के तरीकों के रूप में किसी भी संदर्भ वस्तु पर लागू किया जा सकता है, जैसा कि आगे यहां विस्तृत है

उदाहरण के लिए,

someObject.Evaluate<int>("6 / {{{0}}}", 3))

रिटर्न 3;

someObject.Evaluate("this.ToString()"))

संदर्भ ऑब्जेक्ट का स्ट्रिंग प्रतिनिधित्व लौटाता है;

someObject.Execute(@
"Console.WriteLine(""Hello, world!"");
Console.WriteLine(""This demonstrates running a simple script"");
");

उन बयानों को एक स्क्रिप्ट के रूप में चलाता है, आदि।

एक्ज़ीक्यूटेबल्स को फैक्ट्री मेथड का उपयोग करके आसानी से प्राप्त किया जा सकता है, जैसा कि यहाँ उदाहरण में देखा गया है - और आपको किसी भी अपेक्षित नामित मापदंडों का स्रोत कोड और सूची है (टोकन {ब्रैकेट-नोटेशन, जैसे {{{0}} का उपयोग करके एम्बेड किया गया है) }, स्ट्रिंग के साथ टकराव से बचने के लिए ।फॉर्मैट () और साथ ही हैंडलबार्स-जैसे सिंटैक्स):

IExecutable executable = ExecutableFactory.Default.GetExecutable(executableType, sourceCode, parameterNames, addedNamespaces);

प्रत्येक निष्पादन योग्य वस्तु (स्क्रिप्ट या अभिव्यक्ति) थ्रेड-सुरक्षित है, संग्रहीत और पुन: उपयोग किया जा सकता है, स्क्रिप्ट के भीतर लॉगिंग का समर्थन करता है, समय की जानकारी संग्रहीत करता है और अंतिम अपवाद का सामना करना पड़ता है, आदि। अनुमति देने के लिए प्रत्येक पर एक प्रतिलिपि () विधि भी है सस्ती प्रतियां बनाना, यानी एक स्क्रिप्ट या अभिव्यक्ति से संकलित एक निष्पादन योग्य वस्तु का उपयोग करके दूसरों को बनाने के लिए टेम्पलेट के रूप में।

पहले से संकलित स्क्रिप्ट या कथन को निष्पादित करने का ओवरहेड अपेक्षाकृत कम है, साथ ही मामूली हार्डवेयर पर एक माइक्रोसेकंड के तहत, और पहले से संकलित स्क्रिप्ट और अभिव्यक्तियों को पुन: उपयोग के लिए कैश किया जाता है।


0

मैं नाम से एक संरचना (वर्ग) के सदस्य का मूल्य प्राप्त करने की कोशिश कर रहा था। ढांचा गतिशील नहीं था। सभी उत्तर तब तक काम नहीं करते जब तक कि मुझे अंत में यह नहीं मिला:

public static object GetPropertyValue(object instance, string memberName)
{
    return instance.GetType().GetField(memberName).GetValue(instance);
}

यह विधि सदस्य के मूल्य को उसके नाम से लौटा देगी। यह नियमित संरचना (वर्ग) पर काम करता है।


0

आप हेलेओनिक्स की जाँच कर सकते हैं। चयन पुस्तकालय। यह सदस्यों को गतिशील रूप से / सेट / आह्वान करने के तरीके प्रदान करता है, जिसमें नेस्टेड सदस्य शामिल हैं, या यदि कोई सदस्य स्पष्ट रूप से परिभाषित है, तो आप एक गेट्टर / सेटर (एक प्रतिनिधि में संकलित लैम्ब्डा) बना सकते हैं, जो प्रतिबिंब से तेज है:

var success = Reflector.Set(instance, null, $"Property{i}", value);

या यदि संपत्तियों की संख्या अंतहीन नहीं है, तो आप बसने वालों को उत्पन्न कर सकते हैं और उनका पीछा कर सकते हैं (प्रतिनिधि तेजी से संकलित हैं क्योंकि वे प्रतिनिधि हैं):

var setter = Reflector.CreateSetter<object, object>($"Property{i}", typeof(type which contains "Property"+i));
setter(instance, value);

सेट प्रकार के हो सकते हैं Action<object, object>लेकिन रनटाइम के दौरान उदाहरण अलग-अलग हो सकते हैं, इसलिए आप बसने वालों की सूची बना सकते हैं।


-2

दुर्भाग्य से, C # के पास कोई भी देशी सुविधा नहीं है जो आप पूछ रहे हैं।

हालाँकि, मेरा C # eval प्रोग्राम C # कोड के मूल्यांकन की अनुमति देता है। यह रनटाइम पर C # कोड के मूल्यांकन के लिए प्रदान करता है और कई C # स्टेटमेंट का समर्थन करता है। वास्तव में, यह कोड किसी भी .NET प्रोजेक्ट के भीतर प्रयोग करने योग्य है, हालांकि, यह C # सिंटैक्स का उपयोग करने के लिए सीमित है। अतिरिक्त विवरण के लिए मेरी वेबसाइट http://csharp-eval.com पर एक नज़र डालें ।



-9

सही उत्तर आपको मेमरी उपयोग को कम रखने के लिए सभी परिणाम कैश करने की आवश्यकता है।

एक उदाहरण इस तरह दिखेगा

TypeOf(Evaluate)
{
"1+1":2;
"1+2":3;
"1+3":5;
....
"2-5":-3;
"0+0":1
} 

और इसे सूची में जोड़ें

List<string> results = new List<string>();
for() results.Add(result);

आईडी को सेव करें और कोड में उपयोग करें

उम्मीद है की यह मदद करेगा


5
किसी ने देखने के साथ मूल्यांकन को भ्रमित किया। यदि आप सभी संभावित कार्यक्रमों को जानते हैं (मुझे लगता है कि कम से कम एनपी-हार्ड है) ... और आपके पास सभी संभावित परिणामों को पहले से निर्धारित करने के लिए एक सुपरमैचिन है ... और कोई साइडइफेक्ट्स / बाहरी इनपुट नहीं हैं ... हाँ, यह विचार सैद्धांतिक रूप से काम करता है । कोड एक बड़ा सिंटेक्स त्रुटि है, हालांकि है
sehe
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.