Cum pot evalua dinamic codul C #?

Pot face un eval ("ceva ()"; pentru a executa dinamic codul în JavaScript. Există o cale pentru mine să fac același lucru în C #?

Un exemplu de ce incerc sa fac este: Am o variabila intreaga (sa zic i ) si am mai multe proprietati dupa nume: "Property1", "Property2", "Property3" etc. Acum, vreau să fac anumite operații pe proprietatea "Property i " în funcție de valoarea i .

Acest lucru este foarte simplu cu Javascript. Există vreo modalitate de a face acest lucru cu C #?

0
fr hi bn
@Peter Long, unde pot găsi documentația despre evalul IronPython?
adăugat autor smartcaveman, sursa
c # apela evalul lui ironpython. Am încercat-o în C# 4.0. nici o experiență cu C# 2.0
adăugat autor Peter Long, sursa
adăugat autor Igor Brejc, sursa

15 răspunsuri

Toate acestea ar funcționa cu siguranță. Personal, pentru această problemă anume, probabil aș lua o abordare diferită. Poate ceva de genul:

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

Când utilizați modele asemănătoare, trebuie să aveți grijă ca datele dvs. să fie stocate prin referință și nu prin valoare. Cu alte cuvinte, nu face acest lucru cu primitivi. Trebuie să-ți folosești omologii de clasă mari.

Mi-am dat seama că nu este exact problema, dar întrebarea a fost destul de bine răspunsă și m-am gândit că o abordare alternativă ar putea ajuta.

0
adăugat

Ai putea să o faci cu o funcție prototip:

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

si asa mai departe...

0
adăugat

Nu chiar. Puteți folosi reflecția pentru a obține ceea ce doriți, dar nu va fi la fel de simplu ca în Javascript. De exemplu, dacă doriți să setați câmpul privat al unui obiect la ceva, puteți utiliza această funcție:

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

Din păcate, C# nu este o limbă dinamică de genul asta.

Ce puteți face însă este să creați un fișier de cod sursă C#, plin cu clasă și totul, să îl executați prin intermediul furnizorului CodeDom pentru C# și să îl compilați într-un ansamblu și apoi să-l executați.

This forum post on MSDN contains an answer with some example code down the page somewhat:
create a anonymous method from a string?

Nu aș spune că este o soluție foarte bună, dar este posibil oricum.

Ce fel de cod te aștepți în acel șir? Dacă este un subset minor de cod valid, de exemplu doar expresii matematice, ar putea exista alte alternative.


Edit: Well, that teaches me to read the questions thoroughly first. Yes, reflection would be able to give you some help here.

Dacă împărțiți șirul cu; în primul rând, pentru a obține proprietăți individuale, puteți utiliza următorul cod pentru a obține un obiect PropertyInfo pentru o anumită proprietate pentru o clasă și apoi utilizați acest obiect pentru a manipula un anumit obiect.

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

Link: PropertyInfo.SetValue Method

0
adăugat

Am scris un proiect open source, Dynamic Expresso , care poate converti expresia de text scrisă folosind o sintaxă C# în delegați (sau arbsaue de expresie). Expresiile sunt analizate și transfsaumate în Copaci de expresie fără a utiliza compilația sau reflexia.

Puteți scrie ceva de genul:

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

sau

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

My wsauk is based on Scott Gu article http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .

0
adăugat

Folosește reflecția pentru a analiza și evalua o expresie de legare a datelor față de un obiect la timpul de execuție.

DataBinder.Eval Metoda

0
adăugat
Poți să arăți un exemplu cum?
adăugat autor Nick Binnet, sursa

Nu acum dacă doriți absolut să executați instrucțiuni C#, dar puteți executa deja declarații Javascript în C# 2.0. Biblioteca open source Jint este capabilă să o facă. Este un interpret Javascript pentru .NET. Treceți un program Javascript și acesta va rula în interiorul aplicației. Puteți parcurge chiar și obiectul C# ca argumente și faceți automatizarea pe acesta.

De asemenea, dacă doriți doar să evaluați expresia pe proprietățile dvs., încercați să NCalc .

0
adăugat

Folosind API-ul de scripting Roslyn (mai mult eșantioane aici ):

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

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

Puteți rula, de asemenea, orice bucată de cod:

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

Și trimiteți codul care a fost generat în versiunile precedente:

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

Din păcate, C# nu are niciun fel de facilități native pentru a face exact ceea ce cereți.

Cu toate acestea, programul meu C# eval nu permite evaluarea codului C #. Acesta prevede evaluarea codului C# la timpul de execuție și suportă mai multe instrucțiuni C #. De fapt, acest cod este utilizabil în cadrul oricărui proiect .NET, însă este limitat la utilizarea sintaxei C #. Vizitați site-ul meu, http://csharp-eval.com , pentru detalii suplimentare.

0
adăugat
adăugat autor Andrey-WD, sursa

Puteți utiliza reflexia pentru a obține proprietatea și a o invoca. Ceva de genul:

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

Aceasta este, presupunând că obiectul care are proprietatea se numește "theObject" :)

0
adăugat

De asemenea, puteți implementa un Webbrowser, apoi încărcați un fișier html care conține javascript.

Apoi faceți u pentru metoda document.InvokeScript în acest browser. Valoarea returnată a funcției eval poate fi captată și convertită în tot ceea ce aveți nevoie.

Am făcut acest lucru în mai multe proiecte și funcționează perfect.

Sper ca ajuta

0
adăugat

This is an eval function under c#. I used it to convert anonymous functions (Lambda Expressions) from a string. Source: 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
adăugat
@thehe Whoops, am corectat tipo (Lambada => Lambda). Nu știam că piesa se numește Lambada, așa că aceasta nu a fost intenționată. ;)
adăugat autor Largo, sursa

răspunsul corect este că trebuie să cache întregul rezultat pentru a menține utilizarea memorie scăzută.

un exemplu ar arăta astfel

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

și adăugați-o într-o listă

List results = new List();
for() results.Add(result);

salvați id-ul și utilizați-l în cod

Sper că acest lucru vă ajută

0
adăugat
cineva confuz de evaluare cu căutare. Dacă știți toate programele posibile (I cred că care este cel puțin NP-Hard) ... și aveți un supermachine pentru a precompila toate rezultatele posibile ... și nu există efecte adverse / intrări externe ... Da, această idee funcționează teoretic. Codul este o eroare de sintaxă mare, totuși
adăugat autor sehe, sursa
Uhmmm ... ce vrei să spui?
adăugat autor xfix, sursa

Am scris un pachet, SharpByte .Dynamic , pentru a simplifica sarcina de a compila și executa dinamic codul. Codul poate fi invocat pe orice obiect context folosind metode de extensie, detaliate în continuare aici .

De exemplu,

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

returnează 3;

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

returnează reprezentarea șirului obiectului de context;

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

execută aceste declarații ca scenariu etc.

Executables can be gotten easily using a factory method, as seen in the example here--all you need is the source code and list of any expected named parameters (tokens are embedded using triple-bracket notation, such as {{{0}}}, to avoid collisions with string.Format() as well as Handlebars-like syntaxes):

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

Fiecare obiect executabil (script sau expresie) este sigur, poate fi stocat și reutilizat, suportă logarea din interiorul unui script, stochează informațiile de sincronizare și ultima excepție dacă este întâlnit etc. Există, de asemenea, o metodă Copy() crearea de copii ieftine, adică utilizarea unui obiect executabil compilat dintr-un script sau expresie ca șablon pentru crearea altora.

Operațiunile de executare a unui script sau a unei instrucțiuni deja compilate sunt relativ scăzute, la o foarte mică decadă de hardware modest, iar scripturile și expresiile deja compilate sunt stocate în cache pentru reutilizare.

0
adăugat

Am încercat să obțin o valoare a unui membru de structură (clasă) prin numele său. Structura nu era dinamică. Toate răspunsurile nu au funcționat până când nu am reușit:

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

Această metodă va returna valoarea membrului prin numele său. Funcționează pe o structură obișnuită (clasă).

0
adăugat