[C#] Dynamisch Code zur Laufzeit ausführen

Drucken
( 10 Votes )
Hauptkategorie: Programmieren Kategorie: C#
Erstellt am 23.05.2012 Zuletzt aktualisiert am 23.05.2012 Geschrieben von Jonny132
Diese Tutorial zeigt wie man dem Benutzer die Möglichkeit gibt selber Code zu schreiben. Dieser Code wird dann Just In Time also zur Laufzeit kompiliert und ausgeführt.
Dies funktioniert dank den im .NET zur Verfügung gestellten Namespaces System.CodeDom.Compiler und System.Reflection.

In diesem Tutorial erstellen wir dafür ein neues Windows Forms Projekt mit folgenden Controls:
  • TextBox - Zur Eingabe des Codes vom Benutzer
  • Button - Startet bei Klick den Compiliervorgang und führt den Code aus
  • ListBox - Beinhaltet eventuelle Compilerfehler

Nun wechseln wir in die Codeansicht in der wir die oben angesprochenen NameSpaces per Usingeinbauen:

using System.Reflection;
using System.CodeDom.Compiler;

Der Rest des Codes befindet sich ausschliesslich im Klick-Ereignis des Buttons:

    private void button1_Click(object sender, EventArgs e)
    {
      CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
      CompilerParameters parameters = new CompilerParameters();
      parameters.GenerateInMemory = true;
      parameters.ReferencedAssemblies.Add("System.dll");
      parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");

      StringBuilder sb = new StringBuilder();
      sb.AppendLine(@"using System;");
      sb.AppendLine(@"using System.Windows.Forms;");
      sb.AppendLine(@"public class Test{");
      sb.AppendLine(@"public void Funktion(){");
      sb.AppendLine(textBox1.Text);
      sb.AppendLine(@"}}");

      CompilerResults result = provider.CompileAssemblyFromSource(parameters, sb.ToString());
      listBox1.DataSource = result.Errors;
      listBox1.DisplayMember = "ErrorText";
      if (!result.Errors.HasErrors)
      {
        object instance = result.CompiledAssembly.CreateInstance("Test");
        MethodInfo info = instance.GetType().GetMethod("Funktion");
        info.Invoke(instance, null);
      }
    }
Sieht doch nichteinmal nach soviel Code aus oder?

Code Erklärung:

Zuerst wird eine Instanz der Klasse CodeDomProvider erstellt. Dieser teilen wir mit, dass wir gerne mit der (.NET - Programmier) Sprache 'CSharp' arbeiten wollen.

Damit wir auch die Funktionalität des .NET Frameworks verwenden können, müssen wir eine CompilerParameters - Instanz erzeugen, in der wir die zu Referenzierenden Assemblies angeben können.

Danach erzeugen wir mithilfe eines StringBuilders den Aufbau einer Pseudoklasse, in der wir Usings einfügen und eine Klasse namens 'Test' erstellen welche eine Funktion namens 'Funktion' enthält. In diese Funktion fügen wir den Text (Code) des Users also der TextBox ein.

Somit haben wir den zu kompilierenden Code als Text als Variable und müssen ihn nurnoch kompilieren lassen.
Für diese Aktion benötigen wir wieder unseren CodeDomProvider welcher die Methode CompileAssemblyFromSource() enthält. Dieser können wir unsere definierten Parameter + den Code den wir als StringBuilder Objekt haben übergeben und erhalten ein CompilerResult.

Falls es beim Kompilieren zu Fehlern geführt hat, befinden sich diese in der Errors auflistung des CompilerResults.
Diese können wir bequem an die ListBox binden.
Wurden keine Fehler ausgelöst, können wir mittels Reflection eine Instanz der 'Test'-Klasse erstellen und per MethodInfo.Invoke die Methode 'Funktion' ausführen.





    Veröffentlichen Sie ihre Kommentare ...