CodeDomProvider.CompileAssemblyFromFile 默认不抛异常,需显式检查 results.Errors.HasErrors;常见失败原因包括目标框架不匹配、引用缺失、加载上下文不一致等。

CodeDomProvider.CompileAssemblyFromFile 为什么编译失败但没报错?
默认情况下,CodeDomProvider.CompileAssemblyFromFile 返回的是 CompilerResults 对象,它不会自动抛异常——哪怕所有源文件语法错误、路径不存在、引用缺失,Errors.Count 非零,方法本身也照常返回。很多人卡在这儿,以为“没报错=编译成功”,结果运行时才发现 results.CompiledAssembly 是 null。
- 必须显式检查
results.Errors.HasErrors,而不是只看是否抛了异常 - 错误信息藏在
results.Errors集合里,每条是CompilerError,含Line、Column、ErrorText - 常见静默失败场景:目标框架不匹配(比如用 .NET 6 的
CSharpCodeProvider编译含record的代码,而 provider 实际绑定的是旧版 C# 语言规则) - 调试建议:把
results.Errors全部打印出来,别只取第一条
用 CSharpCodeProvider 动态编译时,如何正确添加引用?
CSharpCodeProvider 不会自动包含 System.dll 以外的常用程序集。像 System.Core、System.Linq、Newtonsoft.Json 这类,必须手动加进 CompilerParameters.ReferencedAssemblies,否则编译直接报 CS0234(类型或命名空间不存在)。
- 基础引用至少补上:
"System.Core.dll"、"System.Data.dll"、"System.Xml.dll" - 第三方 DLL 要用绝对路径,相对路径容易因工作目录变化失效;推荐用
Path.GetFullPath("lib/Newtonsoft.Json.dll") - 注意平台一致性:.NET Framework 下用
CSharpCodeProvider,.NET 5+ 已废弃,得切到Microsoft.CodeAnalysis(Roslyn)方案 - 别漏掉
CompilerParameters.GenerateExecutable = false(默认是true,会试图生成 .exe,但多数动态场景要的是 .dll)
.NET 5+ 还能用 CodeDomProvider 吗?
不能。从 .NET 5 开始,CSharpCodeProvider 被标记为 [Obsolete],且在 .NET 6+ 的默认 SDK 中已移除——即使你强行 NuGet 引入 Microsoft.CodeDom.Providers.DotNetFramework,也只能在 .NET Framework 兼容模式下跑,不适用于纯 .NET Core/.NET 5+ 项目。
- 替代方案只有 Roslyn:
Microsoft.CodeAnalysis.CSharp+CSharpCompilation - Roslyn 编译是内存中完成,无需写临时 .cs 文件,也不依赖本地 csc.exe,可控性更高
- 代价是 API 更底层:要自己构造
SyntaxTree、管理MetadataReference、处理Emit输出流 - 如果只是简单脚本执行,可考虑
CSharpScript(来自Microsoft.CodeAnalysis.Scripting),它封装了编译+执行,但不支持生成可重用的Assembly
动态编译后的 Assembly 为什么一调用就 TypeLoadException?
最常见原因是程序集加载上下文不一致。用 CompileAssemblyFromFile 生成的 Assembly 默认加载进当前上下文,但如果原类型定义在另一个 AssemblyLoadContext(比如插件隔离场景),或编译时引用了不同版本的同一 DLL,运行时就会找不到匹配类型。
- 检查
typeof(MyType).Assembly == results.CompiledAssembly是否成立,避免误用原始类型代替动态类型 - 确保所有被引用的程序集(尤其是泛型约束、接口实现涉及的)版本与编译时完全一致
- 避免跨上下文传递动态类型实例;如需隔离,用
AssemblyLoadContext.CreateCollectible()加载,并在该上下文中创建实例 - 反射调用前,先用
compiledAssembly.GetType("MyNamespace.MyClass")显式获取类型,别依赖Activator.CreateInstance自动解析
动态编译不是黑盒,每个环节都可能断在类型系统边界上。特别是混合使用 CodeDom 和 Roslyn、或在容器/函数计算等受限环境中,加载策略比编译逻辑更易出问题。


















