How can I compile a single code, as a string, into a working and standalone .exe file? I tried three different things:
CSharpCodeProvider: This works fine, but I need it for newer .NET 7 and this solution doesn't work for this version.CSharpScript: This also works fine, but I need to store the actual generated assembly into a working .exe file on disk.CSharpCompiler: I think I need this one, however, I can't get it working, I'm still having some problems with references.
Is there a way of actually adding these references automatically? Always, when I add a reference, it will report that an another reference is missing.
Code I'm using, but doesn't work.
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Reflection;
var code = """
using System;
// Just a demo program.
Console.WriteLine("Hello, World!");
""";
var compilation = CSharpCompilation.Create("DynamicCode")
.WithOptions(new CSharpCompilationOptions(OutputKind.ConsoleApplication))
.AddReferences(
MetadataReference.CreateFromFile(Assembly.Load("System.Private.CoreLib").Location),
MetadataReference.CreateFromFile(Assembly.Load("System").Location)
)
.AddSyntaxTrees(SyntaxFactory.ParseSyntaxTree(code));
// Note: I also tried adding references using the typeof keyword,
// so like typeof(object).Assembly.Location, but that also didn't work.
using var stream = new MemoryStream();
var emitResult = compilation.Emit(stream);
if (emitResult.Success)
{
var exePath = "DynamicCode.exe";
File.WriteAllBytes(exePath, stream.ToArray());
Console.WriteLine($"DynamicCode.exe saved successfully.");
}
else
{
Console.WriteLine("Failed:");
foreach (var diagnostic in emitResult.Diagnostics)
{
Console.WriteLine(diagnostic);
}
}
What I got from the output (compile time):
(4,1): error CS0103: Console name does not exist in the current context.
When I used following references instead of I used in the code:
var compilation = CSharpCompilation.Create("DynamicCode")
.WithOptions(new CSharpCompilationOptions(OutputKind.ConsoleApplication))
.AddReferences(AppDomain.CurrentDomain.GetAssemblies().Select(x => MetadataReference.CreateFromFile(x.Location)))
.AddSyntaxTrees(SyntaxFactory.ParseSyntaxTree(code));
I'm getting this when running the application, plus the output assembly is something about 3kB, which seems weird to me:
Unhandled Exception: System.IO.FileNotFoundException: Unable to load file or assembly System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, or one of its dependencies. The system cannot find the specified file.
So am I doing something wrong? Is there a way of automatically adding references, or some "better" way of adding them? I tried things like ChatGPT, but it didn't help me, so I don't know where is the problem.
If the actual solution worked, is there a way of compiling the assembly into .NET Framework v4.7.2? I want to keep the compatibility with older platforms, but my project is coded in .NET 7, so CSharpCodeProvider cannot be used.