Roslyn Emit API生成的DLL无法引用,如何非反射调用?
使用Roslyn生成DLL后直接引用失败的解决方法
问题描述
我通过Roslyn Emit API生成了.dll文件,生成操作显示成功,但在另一个项目中直接引用该.dll时,抛出System.IO.FileNotFoundException异常,提示找不到程序集“HelloDll”或其依赖项。使用反射加载DLL的方式可以正常工作,但希望无需反射直接调用DLL中的类型。
生成DLL的代码
static void compileToDll() { string codeDll = @""" using System; public class MyClass { public static void RunIt(FEE_BoolSlot slot) { Console.WriteLine("""Hello World!"""); } } """; var tree = CSharpSyntaxTree.ParseText(codeDll); var root = (CompilationUnitSyntax)tree.GetRoot(); var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); options = options.WithPlatform(Platform.AnyCpu); var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location); var compilation = CSharpCompilation.Create( "HelloDll", options:options, references: new[] { mscorlib }) .AddSyntaxTrees(tree); var r = compilation.Emit("example.dll"); }
消费DLL的代码(报错)
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; class Main { static void Main(string[] args) { MyClass2.RunIt(); // 下面这行可以正常工作 // var assembly = Assembly.LoadFile("C:\\...\\example.dll"); } }
解决步骤
1. 修正生成代码的语法错误与依赖
- 字符串转义错误:
codeDll的定义存在语法问题,@"""会导致生成的代码开头多一个引号,正确写法应该是用@"开头,内部双引号用两个双引号转义:string codeDll = @" using System; public class MyClass { public static void RunIt(FEE_BoolSlot slot) { Console.WriteLine(""Hello World!""); } } "; - 缺失依赖引用:代码中使用了
FEE_BoolSlot类型,但当前编译仅引用了mscorlib。如果该类型来自其他程序集,必须添加对应的MetadataReference,否则生成的DLL会有未解决的依赖,导致引用失败:// 示例:添加包含FEE_BoolSlot的程序集引用 var feeAssembly = MetadataReference.CreateFromFile(typeof(FEE_BoolSlot).Assembly.Location); var compilation = CSharpCompilation.Create( "HelloDll", options:options, references: new[] { mscorlib, feeAssembly }) .AddSyntaxTrees(tree); - 检查编译结果:调用
Emit后,务必检查返回结果是否成功,若失败则查看编译诊断信息:var r = compilation.Emit("example.dll"); if (!r.Success) { foreach (var diag in r.Diagnostics) { Console.WriteLine(diag.ToString()); } }
2. 确保DLL被消费项目正确识别
- 正确引用DLL:在消费项目中右键“添加引用”,浏览到生成的
example.dll文件,确保引用路径正确,并且在引用的属性中将“复制本地”设置为True,这样DLL会被复制到消费项目的输出目录。 - 类型名称匹配:消费代码中调用的
MyClass2与生成的类名MyClass不匹配,需修正为MyClass.RunIt(/* 传入FEE_BoolSlot实例 */);,同时消费项目也需要引用包含FEE_BoolSlot的程序集,否则编译时会找不到该类型。
3. 保证DLL路径可被加载
- 生成DLL时最好指定绝对路径,避免相对路径导致的文件找不到问题:
var outputPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "example.dll"); var r = compilation.Emit(outputPath); - 如果生成DLL的程序与消费项目分离,需手动将
example.dll复制到消费项目的输出目录(如bin/Debug/net6.0),或者通过构建事件自动复制。
内容的提问来源于stack exchange,提问作者user1235183
相关产品推荐
相关产品推荐

