使用 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
的输出是:
我的 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 编译时自动解析依赖关系的主要内容,如果未能解决你的问题,请参考以下文章