TLDR;
如何在我的Visual Studio解决方案中查找对索引属性Microsoft.Extensions.Localization.IStringLocalizer.Item[String]
的引用的所有常量字符串参数?所有的源代码都是用C#编写的。该解决方案还必须支持MVC剃刀视图。使用Roslyn在Visual Studio解决方案中查找所有引用
附加信息
我相信罗斯林是这个问题的答案。然而,我还没有找到通过API实现这一目标的方法。我也不确定是使用语法树,编译还是语义模型。以下是基于其他Q & A在此基于stackoverflow的尝试。任何帮助,使其工作是高度赞赏:-)如果你很好奇,你可以阅读这个需要的原因here。
namespace AspNetCoreLocalizationKeysExtractor
{
using System;
using System.Linq;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.MSBuild;
class Program
{
static void Main(string[] args)
{
string solutionPath = @"..\source\MySolution.sln";
var msWorkspace = MSBuildWorkspace.Create();
var solution = msWorkspace.OpenSolutionAsync(solutionPath).Result;
foreach (var project in solution.Projects.Where(p => p.AssemblyName.StartsWith("MyCompanyNamespace.")))
{
var compilation = project.GetCompilationAsync().Result;
var interfaceType = compilation.GetTypeByMetadataName("Microsoft.Extensions.Localization.IStringLocalizer");
// TODO: Find the indexer based on the name ("Item"/"this"?) and/or on the parameter and return type
var indexer = interfaceType.GetMembers().First();
var indexReferences = SymbolFinder.FindReferencesAsync(indexer, solution).Result.ToList();
foreach (var symbol in indexReferences)
{
// TODO: How to get output comprised by "a location" like e.g. a namespace qualified name and the parameter of the index call. E.g:
//
// MyCompanyNamespace.MyLib.SomeClass: "Please try again"
// MyCompanyNamespace.MyWebApp.Views.Shared._Layout: "Welcome to our cool website"
Console.WriteLine(symbol.Definition.ToDisplayString());
}
}
}
}
}
更新:解决方法
尽管@Oxoron我选择诉诸简单的解决方法有很大的帮助。目前Roslyn没有找到使用SymbolFinder.FindReferencesAsync
的任何参考。它似乎是根据“沉默”msbuild失败。这些错误都可以通过这样的:
msWorkspace.WorkspaceFailed += (sender, eventArgs) =>
{
Console.Error.WriteLine($"{eventArgs.Diagnostic.Kind}: {eventArgs.Diagnostic.Message}");
Console.Error.WriteLine();
};
和
var compilation = project.GetCompilationAsync().Result;
foreach (var diagnostic in compilation.GetDiagnostics())
Console.Error.WriteLine(diagnostic);
我的解决方法大致是这样的:
public void ParseSource()
{
var sourceFiles = from f in Directory.GetFiles(SourceDir, "*.cs*", SearchOption.AllDirectories)
where f.EndsWith(".cs") || f.EndsWith(".cshtml")
where !f.Contains(@"\obj\") && !f.Contains(@"\packages\")
select f;
// _["Hello, World!"]
// _[@"Hello, World!"]
// _localizer["Hello, World!"]
var regex = new Regex(@"_(localizer)?\[""(.*?)""\]");
foreach (var sourceFile in sourceFiles)
{
foreach (var line in File.ReadLines(sourceFile))
{
var matches = regex.Matches(line);
foreach (Match match in matches)
{
var resourceKey = GetResourceKeyFromFileName(sourceFile);
var key = match.Groups[2].Value;
Console.WriteLine($"{resourceKey}: {key}");
}
}
}
}
当然解决的办法是不防弹,并依靠命名约定并且不处理多行逐字字符串。但它可能会为我们做的工作:-)
Roslyn Analysys的第一条规则:编写你想要自动显示的代码。 你想查找类似localizer [“anyParam”]的代码吗? – Oxoron
是的,正好@Oxoron :-)我不需要代码分析来处理除了用const字符串调用之外的任何其他特殊情况。 –