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