C# 如何在.NET代码分析器中获取解决方案路径
如何访问Roslyn代码分析器中正在编译的项目/解决方案的文件路径?我需要根据与代码相关的一些存储的规范文件来验证代码。不起作用的事情:C# 如何在.NET代码分析器中获取解决方案路径,c#,.net,roslyn,C#,.net,Roslyn,如何访问Roslyn代码分析器中正在编译的项目/解决方案的文件路径?我需要根据与代码相关的一些存储的规范文件来验证代码。不起作用的事情: SyntaxTreeAnalysisContext.Tree.FilePath Assembly.GetExecutingAssembly().Location AppDomain.CurrentDomain.BaseDirectory Environment.CurrentDirectory Path.GetFullPath(relativePath) 分
SyntaxTreeAnalysisContext.Tree.FilePath
Assembly.GetExecutingAssembly().Location
AppDomain.CurrentDomain.BaseDirectory
Environment.CurrentDirectory
Path.GetFullPath(relativePath)
分析器存在于工作区级别之下(它们直接由编译器运行),因此解决方案可能不存在 由于复杂的原因,它们不是由MEF创建的,所以即使它确实存在,也没有简单的方法来实现它 在VS中,您可以找到全局服务提供商(例如,
ServiceProvider.GlobalProvider
),然后获取scoComponentModel
(VS自己的MEF图的根),并从中获取Roslyn的VisualStudioWorkspace
。请注意,这是一种有点脆弱的方法,在VS之外根本不起作用
即使在VS中,对于预览窗格、杂项文件和其他不属于全局解决方案的上下文中的分析,这也会以奇怪的方式中断;同样易碎,但原因不同。:) 通过从当前语法树的源文件路径开始向上搜索文件夹层次结构,在文件级查找csproj 当然,它在某些情况下不起作用(如果源文件在csproj文件夹的子树之外,例如链接文件;或者周围有其他过时的csproj文件,等等)我能想到的唯一安全网是检查找到的csproj是否真的与当前SemanticModel.Compilation.AssemblyName引用的程序集名称相同,这样我们就不会得到其他随机项目的csproj
下面是代码,请参阅名为FindProjectFile的方法:不经过反射就无法从analyzer或fixer获得解决方案 用于存储设置 在项目中:
<ItemGroup>
<AdditionalFiles Include="MyConfig.config" />
</ItemGroup>
在分析器中:
private const string ConfigFileName = "MyConfig.config";
private static string LoadConfig(ImmutableArray<AdditionalText> additionalFiles, CancellationToken cancellationToken)
{
var file = additionalFiles.SingleOrDefault(f => string.Compare(Path.GetFileName(f.Path), ConfigFileName, StringComparison.OrdinalIgnoreCase) == 0);
if (file == null)
{
return null;
}
var fileText = file.GetText(cancellationToken);
using (var stream = new MemoryStream())
{
using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
{
fileText.Write(writer, cancellationToken);
}
stream.Position = 0;
using (var reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
}
private static void HandleCompilationStart(CompilationStartAnalysisContext context)
{
var config = LoadConfig(context.Options.AdditionalFiles, context.CancellationToken);
}
private const string ConfigFileName=“MyConfig.config”;
私有静态字符串LoadConfig(ImmutableArray附加文件、CancellationToken CancellationToken)
{
var file=additionalFiles.SingleOrDefault(f=>string.Compare(Path.GetFileName(f.Path)、ConfigFileName、StringComparison.OrdinalIgnoreCase)==0);
if(file==null)
{
返回null;
}
var fileText=file.GetText(cancellationToken);
使用(var stream=new MemoryStream())
{
使用(StreamWriter=newstreamwriter(stream,Encoding.UTF8,1024,true))
{
Write(writer,cancellationToken);
}
流位置=0;
使用(变量读取器=新的流读取器(流))
{
返回reader.ReadToEnd();
}
}
}
私有静态void HandleCompilationStart(compilationstartananalysiscontext上下文)
{
var config=LoadConfig(context.Options.AdditionalFiles,context.CancellationToken);
}
我找到了一种通过反射来实现这一点的方法,我只在windows环境中进行了测试
public static class RoslynExtensions
{
public static Solution GetSolution(this SyntaxNodeAnalysisContext context)
{
var workspace = context.Options.GetPrivatePropertyValue<object>("Workspace");
return workspace.GetPrivatePropertyValue<Solution>("CurrentSolution");
}
public static T GetPrivatePropertyValue<T>(this object obj, string propName)
{
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}
var pi = obj.GetType().GetRuntimeProperty(propName);
if (pi == null)
{
throw new ArgumentOutOfRangeException(nameof(propName), $"Property {propName} was not found in Type {obj.GetType().FullName}");
}
return (T)pi.GetValue(obj, null);
}
}
Roslyn分析器存在于工作空间层下方;该解决方案可能实际上并不存在。因此,从定义上讲,这是不可能的?如果您努力尝试,可能可以使其仅在VS中工作(尝试从全球服务提供商处获取SCOComponentModel,然后获取Roslyn VisualStudioWorkspace)。然而,这将是脆弱的,并不会在所有的工作外与@slaks。你真的应该回答问题,而不是仅仅发布一条带有答案的评论。Workspace AnalyzeZeroOptions是内部的,你怎么能这么做谢谢你这样回答最初我找到了一种通过搜索来完成的方法。我稍后会发布一个答案
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeConstDeclaration, SyntaxKind.FieldDeclaration);
}
public static void AnalyzeConstDeclaration(SyntaxNodeAnalysisContext context)
{
var solution = context.GetSolution();
}