如何通过Roslyn程序化创建可直接运行的Windows控制台应用?
解决方案:生成可直接运行的Windows可执行文件
你当前生成的是框架依赖的.NET Core程序集,本质是IL代码,并非原生Windows PE可执行文件,必须依赖dotnet.exe作为CoreCLR宿主才能运行。要生成可直接双击运行的exe,有两种可行方案:
方案一:编译为.NET Framework控制台程序(推荐,实现简单)
如果目标机器已安装.NET Framework(Windows默认预装),可以直接编译为.NET Framework的原生可执行文件,这类exe自带CLR引导逻辑,无需额外宿主。
修改后的代码实现
string codeToCompile = @" using System; public class Program { public static void Main() { Console.WriteLine(""Hello World!""); Console.ReadLine(); } }"; // 解析代码为语法树 var syntaxTree = CSharpSyntaxTree.ParseText(codeToCompile); // 指定.NET Framework程序集路径(以64位4.8版本为例) var netFrameworkDir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.Windows), @"Microsoft.NET\Framework64\v4.0.30319" ); // 引用.NET Framework核心程序集 var refPaths = new[] { Path.Combine(netFrameworkDir, "mscorlib.dll"), Path.Combine(netFrameworkDir, "System.dll"), Path.Combine(netFrameworkDir, "System.Core.dll") }; var references = refPaths.Select(r => MetadataReference.CreateFromFile(r)).ToArray(); // 编译为.NET Framework控制台程序 var compilation = CSharpCompilation.Create("output") .WithOptions(new CSharpCompilationOptions(OutputKind.ConsoleApplication) .WithTargetFramework(TargetFrameworkMoniker.Net48)) .AddReferences(references) .AddSyntaxTrees(syntaxTree); // 输出exe和pdb文件 var emitResult = compilation.Emit("output.exe", "output.pdb"); // 检查编译错误 if (!emitResult.Success) { foreach (var error in emitResult.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error)) { Console.WriteLine($"编译错误:{error.GetMessage()}"); } }
说明
- 生成的
output.exe可直接在安装了.NET Framework 4.8的Windows机器上运行 - 若需适配其他.NET Framework版本,修改
TargetFrameworkMoniker和对应的程序集路径即可
方案二:生成.NET Core/.NET 5+自包含可执行文件
如果需要跨平台支持,或目标机器未安装.NET Framework,可以生成**自包含部署(SCD)**的可执行文件——这类文件包含了CoreCLR运行时和所有依赖库,无需系统预装.NET环境。
Roslyn仅负责编译IL代码,自包含部署需要借助.NET SDK的发布功能,步骤如下:
步骤1:用Roslyn编译生成程序集DLL
string codeToCompile = @" using System; public class Program { public static void Main() { Console.WriteLine(""Hello World!""); Console.ReadLine(); } }"; var syntaxTree = CSharpSyntaxTree.ParseText(codeToCompile); var dotNetCoreDir = Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location); var refPaths = new[] { typeof(Object).GetTypeInfo().Assembly.Location, typeof(Console).GetTypeInfo().Assembly.Location, Path.Combine(dotNetCoreDir, "System.Runtime.dll") }; var references = refPaths.Select(r => MetadataReference.CreateFromFile(r)).ToArray(); // 编译为DLL(而非exe,.NET Core的exe只是宿主存根) var compilation = CSharpCompilation.Create("output") .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) .AddReferences(references) .AddSyntaxTrees(syntaxTree); var emitResult = compilation.Emit("output.dll", "output.pdb"); if (!emitResult.Success) { foreach (var error in emitResult.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error)) { Console.WriteLine($"编译错误:{error.GetMessage()}"); } return; }
步骤2:创建临时项目文件并执行发布
// 定义自包含部署的项目配置(以.NET 6为例) var csprojContent = @"<Project Sdk=""Microsoft.NET.Sdk""> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0</TargetFramework> <SelfContained>true</SelfContained> <RuntimeIdentifier>win-x64</RuntimeIdentifier> <PublishSingleFile>true</PublishSingleFile> <PublishTrimmed>true</PublishTrimmed> </PropertyGroup> <ItemGroup> <Reference Include=""output.dll""> <HintPath>output.dll</HintPath> </Reference> </ItemGroup> </Project>"; // 写入临时项目文件 File.WriteAllText("temp.csproj", csprojContent); // 调用dotnet publish生成自包含可执行文件 var process = new System.Diagnostics.Process(); process.StartInfo.FileName = "dotnet"; process.StartInfo.Arguments = "publish temp.csproj -o publish"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.Start(); string output = process.StandardOutput.ReadToEnd(); string error = process.StandardError.ReadToEnd(); process.WaitForExit(); if (process.ExitCode != 0) { Console.WriteLine($"发布失败:{error}"); } else { Console.WriteLine($"自包含可执行文件已生成:publish\\output.exe"); } // 清理临时文件 File.Delete("temp.csproj");
说明
RuntimeIdentifier可根据目标平台修改(如win-x86、linux-x64)PublishSingleFile可选,开启后会生成单个合并的exe文件PublishTrimmed可选,开启后会裁剪未使用的依赖,减小文件体积
内容的提问来源于stack exchange,提问作者Rafi Henig
相关产品推荐
相关产品推荐

