Frage

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

Ein Beispiel dafür, was ich versuche, ist:Ich habe eine ganzzahlige Variable (z. B i) und ich habe mehrere Eigenschaften mit den Namen:„Eigenschaft1“, „Eigenschaft2“, „Eigenschaft3“ usw.Jetzt möchte ich einige Operationen an der „Eigenschaft“ ausführenich „Immobilien je nach Wert i.

Mit Javascript ist das ganz einfach.Gibt es eine Möglichkeit, dies mit C# zu tun?

War es hilfreich?

Lösung

Leider ist C# keine solche dynamische Sprache.

Was Sie jedoch tun können, ist, eine C#-Quellcodedatei zu erstellen, die alle Klassen und alles enthält, sie über den CodeDom-Anbieter für C# auszuführen, sie in eine Assembly zu kompilieren und sie dann auszuführen.

Dieser Forumsbeitrag auf MSDN enthält eine Antwort mit Beispielcode etwas weiter unten auf der Seite:
Eine anonyme Methode aus einem String erstellen?

Ich würde kaum sagen, dass dies eine sehr gute Lösung ist, aber es ist trotzdem möglich.

Welche Art von Code erwarten Sie in dieser Zeichenfolge?Wenn es sich um eine kleine Teilmenge gültigen Codes handelt, beispielsweise nur um mathematische Ausdrücke, gibt es möglicherweise andere Alternativen.


Bearbeiten:Nun, das lehrt mich, die Fragen zuerst gründlich zu lesen.Ja, Reflektion könnte dir hier weiterhelfen.

Wenn Sie die Zeichenfolge durch das ; teilenUm zunächst einzelne Eigenschaften abzurufen, können Sie mit dem folgenden Code ein PropertyInfo-Objekt für eine bestimmte Eigenschaft einer Klasse abrufen und dieses Objekt dann zum Bearbeiten eines bestimmten Objekts verwenden.

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

Verknüpfung: PropertyInfo.SetValue-Methode

Andere Tipps

Verwenden der Roslyn-Skript-API (mehr Proben hier):

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

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

Sie können auch einen beliebigen Code ausführen:

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

Und verweisen Sie auf den Code, der in früheren Läufen generiert wurde:

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

Nicht wirklich.Sie können Reflektion verwenden, um das zu erreichen, was Sie wollen, aber es wird nicht annähernd so einfach sein wie in Javascript.Wenn Sie beispielsweise das private Feld eines Objekts auf etwas festlegen 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);
}

Dies ist eine Auswertungsfunktion unter c#.Ich habe es verwendet, um anonyme Funktionen (Lambda-Ausdrücke) aus einem String 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;

}

Ich habe ein Open-Source-Projekt geschrieben, Dynamischer Expresso, das mit einer C#-Syntax geschriebene Textausdrücke in Delegaten (oder einen Ausdrucksbaum) konvertieren kann.Ausdrücke werden analysiert und umgewandelt Ausdrucksbäume ohne Kompilierung oder Reflexion zu verwenden.

Sie können so etwas schreiben wie:

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 dem Artikel von Scott Gu http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .

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.Vielleicht so etwas:

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 solcher Muster müssen Sie darauf achten, dass Ihre Daten nach Referenz und nicht nach Wert gespeichert werden.Mit anderen Worten: Tun Sie dies nicht mit Grundelementen.Sie müssen ihre großen, aufgeblähten Klassenkollegen verwenden.

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

Ich weiß jetzt nicht, ob 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#-Objekte als Argumente übergeben und eine Automatisierung daran vornehmen.

Auch wenn Sie nur den Ausdruck Ihrer Eigenschaften auswerten möchten, versuchen Sie es NCalc.

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

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

Das heißt, vorausgesetzt, das Objekt, das die Eigenschaft hat, heißt „theObject“ :)

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

Dann gehst du zum document.InvokeScript Methode in diesem Browser.Der Rückgabewert der Auswertungsfunktion kann abgefangen und in alles umgewandelt werden, was Sie benötigen.

Ich habe das in mehreren Projekten gemacht und es funktioniert perfekt.

Ich hoffe es hilft

Sie könnten es mit einer 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 weiter...

Verwendet Reflektion, um einen Datenbindungsausdruck für ein Objekt zur Laufzeit zu analysieren und auszuwerten.

DataBinder.Eval-Methode

Ich habe ein Paket geschrieben, SharpByte.Dynamic, um die Aufgabe des dynamischen Kompilierens und Ausführens von Code zu vereinfachen.Der Code kann für jedes Kontextobjekt mithilfe von Erweiterungsmethoden aufgerufen werden, wie weiter unten beschrieben Hier.

Zum Beispiel,

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

gibt 3 zurück;

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

gibt die String-Darstellung des Kontextobjekts zurück;

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

führt diese Anweisungen als Skript usw. aus.

Ausführbare Dateien können einfach mithilfe einer Factory-Methode abgerufen werden, wie im Beispiel gezeigt Hier– Alles, was Sie brauchen, ist der Quellcode und eine Liste aller erwarteten benannten Parameter (Tokens werden in der Dreifachklammer-Notation eingebettet, z. B. {{{0}}}, um Kollisionen mit string.Format() sowie Handlers zu vermeiden. wie Syntaxen):

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

Jedes ausführbare Objekt (Skript oder Ausdruck) ist Thread-sicher, kann gespeichert und wiederverwendet werden, unterstützt die Protokollierung innerhalb eines Skripts, speichert Timing-Informationen und die letzte Ausnahme, wenn sie auftritt usw.Außerdem ist jeweils eine Copy()-Methode kompiliert, um die Erstellung kostengünstiger Kopien zu ermöglichen, d. h.Verwenden eines aus einem Skript oder Ausdruck kompilierten ausführbaren Objekts als Vorlage zum Erstellen anderer.

Der Aufwand für die Ausführung eines bereits kompilierten Skripts oder einer Anweisung ist relativ gering und liegt auf bescheidener Hardware deutlich unter einer Mikrosekunde. Außerdem werden bereits kompilierte Skripte und Ausdrücke zur Wiederverwendung zwischengespeichert.

Ich habe versucht, den Wert eines Struktur-(Klassen-)Mitglieds anhand seines Namens zu ermitteln.Die Struktur war nicht dynamisch.Alle Antworten funktionierten nicht, bis ich es endlich bekam:

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

Diese Methode gibt den Wert des Mitglieds anhand seines Namens zurück.Es funktioniert mit regulärer Struktur (Klasse).

Sie könnten das überprüfen Heleonix.Reflexion Bibliothek.Es bietet Methoden zum dynamischen Abrufen/Festlegen/Aufrufen von Mitgliedern, einschließlich verschachtelter Mitglieder, oder wenn ein Mitglied klar definiert ist, können Sie einen Getter/Setter (Lambda in einen Delegaten kompiliert) erstellen, der schneller als Reflektion ist:

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

Oder wenn die Anzahl der Eigenschaften nicht endlos ist, können Sie Setter generieren und zwischenspeichern (Setter sind schneller, da es sich um kompilierte Delegaten handelt):

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

Setter können vom Typ sein Action<object, object> aber Instanzen können zur Laufzeit unterschiedlich sein, sodass Sie Listen von Settern erstellen können.

Leider verfügt C# nicht über native Funktionen, um genau das zu tun, was Sie verlangen.

Allerdings ermöglicht mein C#-Bewertungsprogramm die Auswertung von C#-Code.Es ermöglicht die Auswertung von C#-Code zur Laufzeit und unterstützt viele C#-Anweisungen.Tatsächlich kann dieser Code in jedem .NET-Projekt verwendet werden, er ist jedoch auf die Verwendung der C#-Syntax beschränkt.Werfen Sie einen Blick auf meine Website, http://csharp-eval.com, für weitere Details.

Die richtige Antwort lautet: Sie müssen das gesamte Ergebnis zwischenspeichern, um die Speichernutzung niedrig zu halten.

ein Beispiel würde so aussehen

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

und fügen Sie es einer Liste hinzu

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

Speichern Sie die ID und verwenden Sie sie im Code

hoffe das hilft

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top