2008-08-07 13 views
73

Ich kann eine eval("something()"); ausführen, um den Code dynamisch in JavaScript auszuführen. Gibt es eine Möglichkeit für mich, dasselbe in C# zu tun?Wie kann ich C# -Code dynamisch auswerten?

Was ich genau das zu tun versuchen, ist, dass ich eine Integer-Variable haben (sagen wir i), und ich habe mehrere Eigenschaften mit den Namen: „Property1“, „Property2“, „property3“ usw. Nun, ich möchte um einige Operationen auf der Eigenschaft "Property i" abhängig von dem Wert i durchzuführen.

Dies ist wirklich einfach mit Javascript. Gibt es eine Möglichkeit, dies mit C# zu tun?

+2

C# Aufruf ironpython eval. Ich habe es in C# 4.0 versucht. keine Erfahrung mit C# 2.0 –

+0

@Peter Long, wo finde ich Dokumentation zu IronPython eval? – smartcaveman

+0

Werfen Sie einen Blick auf [Mono CSharp interaktive Shell] (http://www.mono-project.com/CsharpRepl). Es hat [eval ähnliche Funktionen] (http://www.go-mono.com/docs/index.aspx?link=N:Mono.CSharp). –

Antwort

40

Leider C# ist nicht eine dynamische Sprache ähnlich.

Was Sie tun können, ist jedoch, eine C# Quellcode-Datei zu erstellen, voll mit Klasse und allem, und führen Sie es über den CodeDom-Anbieter für C# und kompilieren Sie es in eine Assembly, und führen Sie es dann aus.

Dieses Forum Post auf MSDN enthält eine Antwort mit einigem Beispiel-Code unten auf der Seite etwas:
create a anonymous method from a string?

würde ich kaum sagen, das ist eine sehr gute Lösung, aber es ist trotzdem möglich.

Welche Art von Code werden Sie in dieser Zeichenfolge erwarten? Wenn es sich um eine kleine Teilmenge eines gültigen Codes handelt, beispielsweise nur um mathematische Ausdrücke, könnte es sein, dass andere Alternativen existieren.


bearbeiten: Nun, das mir die Fragen vorher gründlich lesen lehrt. Ja, Reflektion könnte Ihnen hier helfen.

Wenn Sie die Zeichenfolge durch die teilen; Um zum Beispiel einzelne Eigenschaften zu erhalten, können Sie den folgenden Code verwenden, um ein PropertyInfo-Objekt für eine bestimmte Eigenschaft für eine Klasse abzurufen, und dieses Objekt dann zum Bearbeiten eines bestimmten Objekts zu verwenden.

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

-Link: PropertyInfo.SetValue Method

2

Sie können Reflektion verwenden, um die Eigenschaft abzurufen und aufzurufen. Etwas wie folgt aus:

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

Das heißt, das Objekt unter der Annahme, dass die Eigenschaft hat, wird "theObject" genannt :)

0

Man könnte es mit einem Prototyp-Funktion tun:

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

und so auf ...

14

Nicht wirklich. Sie können mit Reflection erreichen, was Sie wollen, aber es wird nicht annähernd so einfach wie in Javascript sein. Zum Beispiel, wenn Sie den privaten Bereich eines Objekts auf etwas setzen möchten, können Sie diese Funktion verwenden:

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

All das würde auf jeden Fall funktionieren. Persönlich würde ich für dieses spezielle Problem wahrscheinlich einen etwas anderen Ansatz wählen.so etwas wie dies vielleicht:

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

Bei der Verwendung von Mustern wie diese, müssen Sie vorsichtig sein, dass Ihre Daten durch Bezugnahme gespeichert sind und nicht von Wert. Mit anderen Worten, tue das nicht mit Primitiven. Sie müssen ihre großen aufgeblähten Klassengegenstücke benutzen.

Ich erkannte, dass das nicht genau die Frage ist, aber die Frage wurde ziemlich gut beantwortet und ich dachte, dass vielleicht ein alternativer Ansatz helfen könnte.

5

Ich nicht jetzt, wenn Sie unbedingt C# -Anweisungen ausführen möchten, aber Sie können bereits Javascript-Anweisungen in C# 2.0 ausführen. Die Open-Source-Bibliothek Jint ist dazu in der Lage. Es ist ein Javascript-Interpreter für .NET. Übergeben Sie ein Javascript-Programm und es wird in Ihrer Anwendung ausgeführt. Sie können sogar C# -Objekt als Argumente übergeben und eine Automatisierung durchführen.

Auch wenn Sie nur Ausdruck auf Ihre Eigenschaften auswerten möchten, versuchen Sie NCalc.

1

Sie könnten auch einen Webbrowser implementieren, dann laden Sie eine HTML-Datei, die Javascript enthält.

Dann gehen Sie für die document.InvokeScript Methode in diesem Browser. Der Rückgabewert der eval-Funktion kann abgefangen und in alles konvertiert werden, was Sie benötigen.

Ich habe dies in mehreren Projekten und es funktioniert perfekt.

Hoffe, dass es

-1

hilft leider C# keine nativen Einrichtungen hat genau für das, was ihr bittet.

Allerdings ermöglicht mein C# eval-Programm die Auswertung von C# -Code. Es ermöglicht die Auswertung von C# -Code zur Laufzeit und unterstützt viele C# -Anweisungen. Tatsächlich ist dieser Code in jedem .NET-Projekt verwendbar, ist jedoch auf die Verwendung von C# -Syntax beschränkt. Weitere Informationen finden Sie auf meiner Website, http://csharp-eval.com.

+0

Werfen Sie einen Blick auf [Roslyn Scripting API] (https://github.com/dotnet/roslyn/wiki/Scripting-API-Samples) –

7

Dies ist eine Evaluierungsfunktion unter C#. Ich habe es verwendet, um anonyme Funktionen (Lambda-Ausdrücke) aus einer Zeichenfolge zu konvertieren. Quelle: 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; 

} 
+0

@sehe Whoops, korrigierte ich den Tippfehler (Lambada => Lambda). Ich wusste nicht, dass das Lied Lambada heißt, also war dieses nicht beabsichtigt. ;) – Largo

-7

die richtige Antwort ist, dass Sie alle das Ergebnis zwischenspeichern müssen die mem0ry Nutzung gering zu halten.

wäre ein Beispiel so aussehen

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

und es zu einer Liste hinzufügen

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

die ID speichern und im Code verwenden

hoffe, das hilft

+0

Uhmmm ...Was meinen Sie? – xfix

+3

jemand verwirrt Auswertung mit Nachschlagen. Wenn du alle möglichen Programme kennst (ich denke, das ist zumindest _ NP-Hard) ... und du hast eine Supermaschine, um alle möglichen Ergebnisse vorzukompilieren ... ** und ** es gibt keine Nebeneffekte/externe Eingaben. .. Ja, diese Idee _theoretisch_ funktioniert. Der Code ist ein großer Syntaxfehler, obwohl – sehe

0

Verwendet Reflektion zum Analysieren und Auswerten eines Datenbindungsausdrucks für ein Objekt zur Laufzeit.

DataBinder.Eval Method

+0

Können Sie ein Beispiel wie zeigen? –

7

Ich habe ein Open Source Projekt geschrieben, Dynamic Expresso, der Text Ausdruck konvertieren kann unter Verwendung einer C# Syntax in Teilnehmer (oder Ausdrucksbaum) geschrieben.Ausdrücke werden geparst und in Expression Trees umgewandelt, ohne Kompilierung oder Reflektion zu verwenden.

Sie können so etwas wie schreiben:

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

oder

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

Meine Arbeit basiert auf Scott Gu Artikel http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx.

6

die API Roslyn Scripting (mehr samples here):

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

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

Sie auch jedes Stück Code ausführen kann:

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

Und den Code verweisen, die in früheren Läufen generiert wurde:

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

Ich habe ein Paket geschrieben, SharpByte.Dynamic, um die Aufgabe zu vereinfachen o f Kompilieren und Ausführen von Code dynamisch. Der Code kann für jedes Kontextobjekt unter Verwendung von Erweiterungsmethoden aufgerufen werden, wie weiter unten beschrieben here.

Zum Beispiel

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

kehrt 3;

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

gibt die Stringdarstellung des Kontextobjekts zurück;

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

läuft diese Aussagen als Skript usw.

Executables eine Factory-Methode werden kann, wie leicht verwenden, here im Beispiel zu sehen bekommen --alle Sie brauchen, ist der Quellcode und die Liste aller erwarteten benannte Parameter (unter Verwendung von triple-Dirac-Notation, Token eingebettet sind, wie beispielsweise {{{0}}}, zur Vermeidung von Kollisionen mit string.Format() sowie Lenkern artige Syntaxen):

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

Jedes ausführbaren Objekt (Skript oder Ausdruck) ist Thread-sicher, kann gespeichert werden d und reused, unterstützt die Protokollierung von innerhalb eines Skripts, speichert Timing-Informationen und die letzte Ausnahme, falls aufgetreten, usw. Es gibt auch eine Copy() -Methode, die auf jedem kompiliert werden kann, um billige Kopien zu erstellen, dh ein ausführbares Objekt, das aus einem Skript oder einem Ausdruck kompiliert wurde als Vorlage zum Erstellen anderer.

Overhead der Ausführung eines bereits kompilierten Skripts oder einer Anweisung ist relativ niedrig, auf weniger als einer Mikrosekunde auf bescheidener Hardware, und bereits kompilierte Skripts und Ausdrücke werden zur Wiederverwendung zwischengespeichert.