使用 Roslyn 编译时自动解析依赖关系

Posted

技术标签:

【中文标题】使用 Roslyn 编译时自动解析依赖关系【英文标题】:Automatically resolving dependencies when compiling using Roslyn 【发布时间】:2017-05-24 17:21:14 【问题描述】:

我目前正在编写一个应用程序,该应用程序当前通过 Roslyn 的工作区 API 加载项目,将指定的 C# 文件转换为语法树,然后从它创建一个内存程序集,然后最终提取 IL。

这一切正常,但是只要我在所述 C# 文件中引用任何外部库,编译就会失败,因为 Roslyn 不知道在哪里解析这些引用。

这是我目前正在做的简化版本:

元数据引用 [] 元数据引用 = MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(Uri).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(DynamicAttribute).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(AssemblyMetadata).GetTypeInfo().Assembly.Location), ; var sourceLanguage = new CSharpLanguage(); var syntaxTree = sourceLanguage.ParseText(sourceCode, SourceCodeKind.Regular); var options = new CSharpCompilationOptions( OutputKind.DynamicallyLinkedLibrary, 优化级别:优化级别。调试, 允许不安全:真 ); CSharpCompilation 编译 = CSharpCompilation.Create("ExampleAssembly", options: options); var 流 = 新的 MemoryStream(); var 结果 = 编译。 添加引用(元数据引用) .AddSyntaxTrees(syntaxTree) .Emit(流); // 成功为假 如果(!emitResult.Success) foreach(emitResult.Diagnostics 中的 var 诊断) Debug.WriteLine(diagnostic.ToString());

Debug.WriteLine 的输出是:

(1,7):错误 CS0246:找不到类型或命名空间名称“MediatR”(您是否缺少 using 指令或程序集引用?) (9,32):错误 CS0246:找不到类型或命名空间名称“Mediator”(您是否缺少 using 指令或程序集引用?)

我的 Roslyn 项目正在读取的文件就是这样的:

使用 MediatR; 命名空间控制台应用程序 公开课程序 公共静态无效主要(字符串[]参数) var mediator = new Mediator(null, null);

我的问题是,Roslyn 是否提供 API 来自动加载文件可能具有的任何依赖项?我希望 Roslyn 工作区允许这样做,但我找不到任何东西。

【问题讨论】:

你确定这是由于无法加载引用,而不是例如一些语法错误?向我们展示确切的编译器错误。 我已经更新了我的问题以包含错误输出和我正在阅读的文件。 那么,您希望using MediatR; 指令能够解析您的库吗?这就是 CSharpScript 中有 #r <path> 的原因。甚至MetadataReferences 也需要解决,参见MetadataReferenceResolver。我能想到的实现这一点的唯一方法是#1 编译,#2 检查已知错误,尝试添加引用,转到#1。但即使这样也不适用于共享命名空间的扩展方法等...... @m0sa 不,这不是 C# 脚本文件。我的意图是编译从项目工作区中提取的随机 C#。 当您说您正在“从项目”加载文件时,您是否有 .csproj 或 project.json 或其他东西可供查看? 【参考方案1】:

如果 MediatR 控制台项目是 project.json 项目,那么您可以使用来自 "Microsoft.DotNet.ProjectModel.Workspaces": "1.0.0-preview2-1-003177"ProjectJsonWorkspace。您可以将它指向您的project.json 并获得一个Compilation 对象,这将为您完成获取项目引用、文件引用等的所有艰苦工作......然后您可以从这里发出您的IL。

这是一个例子:

var compilation = new ProjectJsonWorkspace(@"PathToYour\project.json").CurrentSolution.Projects.First().GetCompilationAsync().Result;

var stream = new MemoryStream();
var emitResult = compilation.Emit(stream);

或者如果您需要完全控制,您可以继续使用CSharpCompilation.Create,从此处的compilation 对象中复制您需要的内容,并传入SyntaxTree

希望对您有所帮助。

【讨论】:

完美,ProjectJsonWorkspace 正是我想要的,谢谢!

以上是关于使用 Roslyn 编译时自动解析依赖关系的主要内容,如果未能解决你的问题,请参考以下文章

NestJS 无法解析 AuthServices 的依赖关系

Makefile学习7————自动生成依赖关系 三颗星

如何通过自动生成的makefile 看各个文件的依赖关系

ASP.NET Core使用编译时依赖关系注入(DI)

自动生成依赖关系

无法解析“:app@debug/compileClasspath”的依赖关系:无法解析