Benutzer mit den meisten Antworten
String als Code oder "Interpreter-Emulation"... Zeichenkette als Funktion

Frage
-
Hallo,
leider gibt es ja kein "eval" wie in der "guten" (?), alten (!) und kruden Programmiersprache XBase++ in C#. Dennoch würde mich interessieren, wie man dieses Verhalten möglichst simpel (keine Sicherheitsaspekte und Ähnliches) in C# nachbilden kann.
Konkreter: natürlich ist es möglich, einer Variablen einen Lambda-Ausdruck zuzuweisen und diese Variable auf Daten anzuwenden. Den Lambda-Ausdruck muss ich aber im Code hinschreiben. Wenn ich aber zur Design-Zeit noch nicht genau weiß, wie der Lambda-Ausdruck (oder auch etwas ganz anderes, halt ein sinnvolles Code-Fragment) zur Laufzeit aussieht, bringt mir das nicht viel. Triviales Beispiel (trivial, weil dämlich, weil viel einfacher lösbar, aber anschaulich):
public float Brutto(float netto, float mwstInProzent) { return netto * (1 + mwstInProzent / 100); }
...
var brutto = Brutto(netto, Consts.GermanVATInPercent);wäre naheliegend. Es ginge aber auch
public float Brutto(float netto) { return netto * 1.19; }
...
var brutto = Brutto(netto);Was ich nun suche, würde in Pseudocode so aussehen:
var Brutto = (Code)"return netto * (1 + " + Consts.GermanVATInPercent.ToString() + " / 100);";
...
var Brutto = Brutto(netto);Der Typecast kann natürlich auch sonstwie aussehen, eine Methode, irgendwas, aber eben so einfach wie möglich.
MfG
Carsten Posingies
Antworten
-
Hallo,
.NET bietet auch so eine Art eval an - dabei wird der jeweilige .NET Code kompiliert. Das entspricht dem, was in dem verlinkten Codeproject Beitrag beschrieben ist. Ich kann den Code bei mir Problemlos ausführen:public static void HelloWorld() { string code = @" using System; namespace First { public class Program { public static void Main() { " + "Console.WriteLine(\"Hello, world!\");" + @" } } } "; CSharpCodeProvider provider = new CSharpCodeProvider(); CompilerParameters parameters = new CompilerParameters(); // Reference to System.Drawing library parameters.ReferencedAssemblies.Add("System.Drawing.dll"); // True - memory generation, false - external file generation parameters.GenerateInMemory = true; // True - exe file generation, false - dll file generation parameters.GenerateExecutable = true; CompilerResults results = provider.CompileAssemblyFromSource(parameters, code); if (results.Errors.HasErrors) { StringBuilder sb = new StringBuilder(); foreach (CompilerError error in results.Errors) { sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText)); } throw new InvalidOperationException(sb.ToString()); } Assembly assembly = results.CompiledAssembly; Type program = assembly.GetType("First.Program"); MethodInfo main = program.GetMethod("Main"); main.Invoke(null, null); }
Darum ist es wichtig, das du uns sagst, wo der Fehler auftritt und welche zusätzlichen Informationen du bekommst. Zeige bitte auch deinen aktuellen Code dazu.
Eine andere Möglichkeit besteht natürlich darin einen eigenen Parser zu schreiben. Du scheinst es aber speziell auf C# spezifische Syntax abzusehen, weswegen CodeDom der einfacherere sein dürfte.
Tom Lambert - C# MVP
Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets- Als Antwort vorgeschlagen Aleksander Chalabashiev Freitag, 24. Oktober 2014 14:45
- Als Antwort markiert Aleksander Chalabashiev Dienstag, 28. Oktober 2014 10:26
Alle Antworten
-
Nachtrag: Eine Lösung habe ich gefunden, die leider nicht funktioniert:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime
Da steigt es mit einer System.IO.FileNotFoundException aus.
-
Hallo,
.NET bietet auch so eine Art eval an - dabei wird der jeweilige .NET Code kompiliert. Das entspricht dem, was in dem verlinkten Codeproject Beitrag beschrieben ist. Ich kann den Code bei mir Problemlos ausführen:public static void HelloWorld() { string code = @" using System; namespace First { public class Program { public static void Main() { " + "Console.WriteLine(\"Hello, world!\");" + @" } } } "; CSharpCodeProvider provider = new CSharpCodeProvider(); CompilerParameters parameters = new CompilerParameters(); // Reference to System.Drawing library parameters.ReferencedAssemblies.Add("System.Drawing.dll"); // True - memory generation, false - external file generation parameters.GenerateInMemory = true; // True - exe file generation, false - dll file generation parameters.GenerateExecutable = true; CompilerResults results = provider.CompileAssemblyFromSource(parameters, code); if (results.Errors.HasErrors) { StringBuilder sb = new StringBuilder(); foreach (CompilerError error in results.Errors) { sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText)); } throw new InvalidOperationException(sb.ToString()); } Assembly assembly = results.CompiledAssembly; Type program = assembly.GetType("First.Program"); MethodInfo main = program.GetMethod("Main"); main.Invoke(null, null); }
Darum ist es wichtig, das du uns sagst, wo der Fehler auftritt und welche zusätzlichen Informationen du bekommst. Zeige bitte auch deinen aktuellen Code dazu.
Eine andere Möglichkeit besteht natürlich darin einen eigenen Parser zu schreiben. Du scheinst es aber speziell auf C# spezifische Syntax abzusehen, weswegen CodeDom der einfacherere sein dürfte.
Tom Lambert - C# MVP
Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets- Als Antwort vorgeschlagen Aleksander Chalabashiev Freitag, 24. Oktober 2014 14:45
- Als Antwort markiert Aleksander Chalabashiev Dienstag, 28. Oktober 2014 10:26