C#通过Roslyn获取代码中的引用及签名
Roslyn可以对代码进行分析,查找代码并替换代码。参考文档如下:
https://roslynquoter.azurewebsites.net/
https://devblogs.microsoft.com/visualstudio/roslyn-syntax-visualizers/
https://jonskeet.uk/csharp/index.html
https://joshvarty.com/2014/07/06/learn-roslyn-now-part-2-analyzing-syntax-trees-with-linq/
https://joshvarty.com/learn-roslyn-now/
有这么一个需求:找到代码中所有的引用并打印出来。
如果是手动查找的话,容易出错且工作量比较大,因此通过Roslyn可以自动地将代码的信息提取出来。步骤如下:
1.DemoApp,一个简单的函数,有四个地方引用这个函数,现在需要做的是通过Roslyn查找四个引用
class Program
{
/// <summary>
/// 方法入口123
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
var c1 = Plus(1, 2);
var c2 = Plus(3, 4);
var c3 = Plus(5,55);
var c4 = Plus(6, 666);
}
static int Plus(int a,int b)
{
return a + b;
}
}
2.初始化Roslyn
初始化包含: MSBuildLocator.RegisterDefaults(); MSBuildWorkspace.Create(); workspace.OpenSolutionAsync() 等方法。
Init();
var workspace = MSBuildWorkspace.Create();
workspace.SkipUnrecognizedProjects = true;
workspace.LoadMetadataForReferencedProjects = false;
workspace.WorkspaceFailed += Workspace_WorkspaceFailed;
var solution = workspace.OpenSolutionAsync(@"D:\测试代码\2022-06-27-DemoApp\2022-06-27-DemoApp.sln").Result;
3.找到引用:
var machineMgrProj = solution.Projects.FirstOrDefault(x => x.Name == projectName);
var sysLogDoc = machineMgrProj.Documents.FirstOrDefault(x => x.Name == csFileName);
var semanticModel2 = sysLogDoc.GetSemanticModelAsync().Result;
var rootNode2 = sysLogDoc.GetSyntaxRootAsync().Result;
var nodeClass = rootNode2.DescendantNodes().OfType<ClassDeclarationSyntax>()
.FirstOrDefault(x => x.Identifier.ToString() == className1);
var nodeMethod = nodeClass.DescendantNodes()
.OfType<MethodDeclarationSyntax>().FirstOrDefault(x => x.Identifier.ToString() == methodName && x.ParameterList.ToString() == methodParListString);
var sampleMethodSymbol1 = semanticModel2.GetDeclaredSymbol(nodeMethod);
var referencesToSampleMethod2 = SymbolFinder.FindReferencesAsync(sampleMethodSymbol1, solution).Result;
4.解析引用:
//文件名
var fileName = location.Document.Name;
//syntex tree
var syntaxTree = location.Location.SourceTree;
var root = syntaxTree.GetRoot();
//class node
var cc1c = root.DescendantNodes().OfType<ClassDeclarationSyntax>().First();
//类名
var className = cc1c.Identifier.ValueText;
if (!fileName.Contains(".cs"))
{
}
//location node-inovation node
var nodeFind = syntaxTree.GetRoot().FindNode(location.Location.SourceSpan);
//method node
var parentMethod = GetParentMethod<MethodDeclarationSyntax>(nodeFind);
//方法名
var methodName1 = parentMethod.Identifier.ValueText;
//方法注释
//method token
var t1 = parentMethod.DescendantTokens();
var t2 = t1
.Where(x => x.IsKind(SyntaxKind.PrivateKeyword) || x.IsKind(SyntaxKind.PublicKeyword) ||
x.IsKind(SyntaxKind.ProtectedKeyword)||x.IsKind(SyntaxKind.StaticKeyword)).FirstOrDefault();
//token的细节信息
var trivia = t2.LeadingTrivia.Where(x =>
x.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) ||
x.IsKind(SyntaxKind.MultiLineCommentTrivia))
.FirstOrDefault();
var comment = GetComment(trivia);
//参数
var invocation = GetParentMethod<InvocationExpressionSyntax>(nodeFind);
var parameter = invocation.DescendantNodes().OfType<ArgumentListSyntax>()
.Where(x => x.Span.Start >= nodeFind.Span.End).First();
var argumentss = parameter.DescendantNodes().OfType<ArgumentSyntax>().ToList();
最后,效果如下图,查找到了4个引用,及引用的参数值

源码下载:https://files.cnblogs.com/files/congqiandehoulai/%E6%B5%8B%E8%AF%95N%E6%96%B9%E6%B3%95%E6%AC%A1%E6%95%B0_2.rar
https://files.cnblogs.com/files/congqiandehoulai/2022-06-27-DemoApp.rar
浙公网安备 33010602011771号