Code-Compilation: Wie C# Code magisch zur EXE wird!

Die Fragestellung ist wie kann ich on “the fly” c# Code kompilieren in .NET 9.0

Als Demo machen wir ein kleines Programm, das eine beliebige Datei mit C# Code kompiliert und eine DLL erstellt.

Das grundlegende Gerüst des Programms ist relativ einfach.

Grundlegend brauchen wir zum Einbau eines C’ Compilers in eine Anwendung nicht viel.

Wir müssen nur das Microsoft.CodeAnalysis Paket installieren und schon können wir im Code kompilieren.

var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(sourceCode));

var assemblyPath = Path.ChangeExtension(Path.GetTempFileName(), "exe");

var compilation = CSharpCompilation.Create(Path.GetFileName(assemblyPath))
    .WithOptions(new CSharpCompilationOptions(OutputKind.ConsoleApplication))
    .AddSyntaxTrees(syntaxTree);

var result = compilation.Emit(assemblyPath);

if (result.Success)
{
    Process.Start(assemblyPath);
}
else
{
    Debug.Write(string.Join(
        Environment.NewLine,
        result.Diagnostics.Select(diagnostic => diagnostic.ToString())
    ));
}

Eigentlich ist das der ganze Code den wir brauchen.
Leider kommen Fehler, da wir einige wichtige Referenzen vergessen haben hinzuzufügen.

Diese Referenzen können wir ganz einfach CSharpCompilation hinzufügen. Das Property heißt treffend references.

Also fügen wir die wichtigsten Assemblies hinzu

  var references = new List<MetadataReference>
  {
      MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
      MetadataReference.CreateFromFile(typeof(Console).Assembly.Location),
      MetadataReference.CreateFromFile(typeof(Decimal).Assembly.Location),
      MetadataReference.CreateFromFile(typeof(Object).Assembly.Location),
      MetadataReference.CreateFromFile(Path.Combine(runtimePath, "mscorlib.dll")),
      MetadataReference.CreateFromFile(typeof(System.Runtime.AssemblyTargetedPatchBandAttribute).Assembly.Location),
      MetadataReference.CreateFromFile(typeof(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo).Assembly.Location),
      MetadataReference.CreateFromFile(Path.Combine(runtimePath, "System.Runtime.dll")),
      MetadataReference.CreateFromFile(Path.Combine(runtimePath, "System.Console.dll")),
      MetadataReference.CreateFromFile(Path.Combine(runtimePath, "System.Core.dll")),
         // Explizit CoreLib referenzieren
      MetadataReference.CreateFromFile(Path.Combine(runtimePath, "System.Private.CoreLib.dll")),
      // Weitere wichtige Basis-Assemblies
      MetadataReference.CreateFromFile(Path.Combine(runtimePath, "System.Collections.dll")),
      MetadataReference.CreateFromFile(Path.Combine(runtimePath, "System.Linq.dll")),
      MetadataReference.CreateFromFile(Path.Combine(runtimePath, "System.Threading.dll")),

      MetadataReference.CreateFromFile(typeof(System.Composition.Convention.AttributedModelProvider).Assembly.Location), //System.Composition.AttributeModel
      MetadataReference.CreateFromFile(typeof(System.Composition.Convention.ConventionBuilder).Assembly.Location),   //System.Composition.Convention
      MetadataReference.CreateFromFile(typeof(System.Composition.Hosting.CompositionHost).Assembly.Location),        //System.Composition.Hosting
      MetadataReference.CreateFromFile(typeof(System.Composition.CompositionContext).Assembly.Location),             //System.Composition.Runtime
      MetadataReference.CreateFromFile(typeof(System.Composition.CompositionContextExtensions).Assembly.Location),   //System.Composition.TypedParts

  };

So weit so gut – nur ganz funktioniert das Ganze noch nicht. Da folgender Fehler auftritt:

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly ‘System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e’ or one of its dependencies. The system cannot find the file specified.

Das liegt daran das ein File fehlt: *.runtimeconfig.json

Dieses müssen wir noch erzeugen und schon funkt unser Programm.

Den ganzen Source Code findest Du unter: https://github.com/gpiwonka/CompilerDemo

Leave a Comment




Enter Captcha Here :