在Roslyn中添加引用报错:FileNotFoundException无法加载程序集
Roslyn加载依赖程序集报错的解决方案
问题现象
即使通过CreateFromStream或CreateFromFile方法为Roslyn编译添加了依赖程序集的元数据引用,编译成功后加载生成的程序集时仍抛出如下错误:
FileNotFoundException: 无法加载文件或程序集'SimpleLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'。系统找不到指定的文件。
问题原因
Roslyn编译阶段仅依赖元数据引用完成语法和语义检查,但运行时CLR需要找到依赖程序集的实际文件才能加载。如果依赖程序集不在CLR的默认搜索路径中,就会触发找不到文件的异常。
解决方案
方案一:将依赖程序集放入CLR搜索路径
- 把
SimpleLibrary.dll复制到当前应用程序的输出目录(如bin/Debug/net6.0); - 或者将
SimpleLibrary.dll所在的目录(如d:\)添加到系统PATH环境变量中; - 这样CLR在加载生成的程序集时,就能自动找到依赖文件。
方案二:通过AssemblyResolve事件加载内存中的依赖
如果不想复制物理文件,可以在加载生成的程序集前,注册AppDomain.CurrentDomain.AssemblyResolve事件,当CLR找不到依赖时,从内存中直接加载对应的程序集。
修改后的完整代码示例:
using System; using System.IO; using System.Reflection; using System.Collections.Generic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; List<MetadataReference> references = new List<MetadataReference>(); // 读取依赖程序集到内存,保留字节数组供后续加载使用 byte[] libraryBytes = File.ReadAllBytes(@"d:\SimpleLibrary.dll"); using (Stream stream = new MemoryStream(libraryBytes)) { references.Add(MetadataReference.CreateFromStream(stream)); } string code = @" using SimpleLibrary; namespace RoslynCompileSample { public class Program { public bool Main() { return true; } } }"; // 创建编译对象(原代码中缺失的关键部分) var compilation = CSharpCompilation.Create( "RoslynCompileSampleAssembly", syntaxTrees: new[] { CSharpSyntaxTree.ParseText(code) }, references: references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); using (var ms = new MemoryStream()) { try { EmitResult result = compilation.Emit(ms); if (result.Success) { ms.Seek(0, SeekOrigin.Begin); byte[] compiledAssemblyBytes = ms.ToArray(); // 注册程序集解析事件,处理依赖加载 AppDomain.CurrentDomain.AssemblyResolve += (sender, resolveArgs) => { var targetAssemblyName = new AssemblyName(resolveArgs.Name); if (targetAssemblyName.Name.Equals("SimpleLibrary", StringComparison.OrdinalIgnoreCase)) { return Assembly.Load(libraryBytes); } return null; }; // 加载生成的程序集并执行方法 Assembly assembly = Assembly.Load(compiledAssemblyBytes); Type programType = assembly.GetType("RoslynCompileSample.Program"); object instance = Activator.CreateInstance(programType); var methodResult = programType.InvokeMember( "Main", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, instance, null); } else { // 输出编译错误信息 foreach (var diagnostic in result.Diagnostics) { Console.WriteLine(diagnostic.ToString()); } } } catch (Exception ex) { Console.WriteLine($"执行出错:{ex.ToString()}"); } }
注意事项
- 如果存在多个依赖程序集,需要在
AssemblyResolve事件中逐一处理每个缺失的程序集; - 确保保存依赖程序集字节数组的变量(如
libraryBytes)在事件触发时未被回收,需保持其生命周期覆盖程序集加载阶段; - 原代码中缺失了
CSharpCompilation对象的创建逻辑,这是Roslyn编译的核心步骤,必须补充完整。
内容的提问来源于stack exchange,提问作者MB_18
相关产品推荐
相关产品推荐

