NCoreCoder.Aop已经写了好一段时间了,一直不温不火的,自己摸索技术也需要沉下心来深耕
写完AOP的时候,一时感慨,纸上得来终觉浅,阅读到WebApiClient的时候,发现了一个宝贝,静态分析器~
遂查询资料,自己打磨了一个基于NCoreCoder.Aop的静态分析器,做什么呢~代码自检啊,使用NCoreCoder.Aop的时候,增加一些自动化提示
踩坑了几天,非常感谢walterlv(吕毅)大佬的博文以及资料,也陪我踩坑,非常感谢这个前辈
博客园链接https://www.cnblogs.com/walterlv/ 他的最新自建博客链接 https://walterlv.com/
分享文章,这样,我们可以自己打造自己的分析器,这个对于团队而言,增加了一定的代码检测保护
编写前
工欲善其事,必先利其器,我们先安装Syntax Visualizer
参考资料https://blog.walterlv.com/post/roslyn-syntax-visualizer.html
如果你是 Visual Studio 2017 / 2019,并且在安装 Visual Studio 时选择了 Visual Studio 扩展开发的工作负载,并且已经勾选了 .NET Compiler Platform SDK,那么你就已经安装好了。如果没有找到,请前往 如何安装和准备 Visual Studio 扩展/插件开发环境 - walterlv 再安装。如果你的 Visual Studio 版本比较旧,则需要去 .NET Compiler Platform SDK - Visual Studio Marketplace 下载安装。
安装完之后,去“视图->其它窗口”中就可以找到“Syntax Visualizer”。
按照好后,确认一下 视图->其他窗口,看见Syntax Visualizer
这样就算是成功了
上面那段引用文字要认真看,别学我,搞了半天发现找不到不对,摘抄自walterlv大佬的原文,无歧义
我们新建一个分析器
在已有的解决方案上,选中解决方案,单击右键添加,选择新建项目,在Extensibility选型中,选择Analyzer with Code Fix(.NET Standard)
选择确定,会自动创建出三个项目,比如我们的项目叫Analyzer
会自动创建出"Analyzer" "Analyzer.Test" "Analyzer.Vsix" 我们要调试分析器的话,就选择“Analyzer.Vsix”作为启动项目,运行会自动重启一个VS,这个VS用来启动我们要调试的项目
打开AnalyzerAnalyzer.cs,删除掉自动生成的多余代码
[DiagnosticAnalyzer(LanguageNames.CSharp)] public class AnalyzerAnalyzer : DiagnosticAnalyzer { public const string DiagnosticId = "Analyzer"; public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create<DiagnosticDescriptor>(); public override void Initialize(AnalysisContext context) { } }
DiagnosticAnalyzerAttribute表示要监视分析的语言
点开LanguageNames这个静态类,发现支持C#、F#、VB?确定不是VB .Net?
编写分析器
打开Syntax Visualizer
我们写一个简单的接口
public interface IService { }
鼠标选中接口,我们看看 Syntax Visualizer
因为我们是静态分析代码,就不关注其他API了
就关注AnalysisContext.RegisterSyntaxNodeAction即可
编写一个分析器基类
public abstract class BaseAnalyzContext {
public abstract DiagnosticDescriptor[] SupportedDiagnostics { get; } public abstract void Execute(SyntaxNodeAnalysisContext context); }
附上分析器代码段
public class AnalyzerAnalyzer : DiagnosticAnalyzer { private BaseAnalyzContext[] Contexts = new BaseAnalyzContext[] { new InterfaceAnalyzerContext() }; public const string DiagnosticId = "Analyzer"; public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } public AnalyzerAnalyzer() { var diagnosticDescriptors = new List<DiagnosticDescriptor>(); foreach (var analyzer in Contexts) { diagnosticDescriptors.AddRange(analyzer.SupportedDiagnostics); } SupportedDiagnostics = ImmutableArray.Create(diagnosticDescriptors.ToArray()); } public override void Initialize(AnalysisContext context) { context.RegisterSyntaxNodeAction(SyntaxNodeAction, SyntaxKind.InterfaceDeclaration); } private void SyntaxNodeAction(SyntaxNodeAnalysisContext context) { foreach(var analyzer in Contexts) { analyzer.Execute(context); } } }
我们实现一个简单的接口验证,判断接口是否以大写I开头,且Interface结尾,否则抛出错误,中止
public class InterfaceAnalyzerContext : BaseAnalyzContext { public override DiagnosticDescriptor[] SupportedDiagnostics => new DiagnosticDescriptor[] { InterfaceName }; private static DiagnosticDescriptor InterfaceName = new DiagnosticDescriptor("I001", "接口验证", "接口名称错误,应该是I{0}Interface", "Error", DiagnosticSeverity.Error, True); public override void Execute(SyntaxNodeAnalysisContext context) { if (context.Node.Kind() == SyntaxKind.InterfaceDeclaration) { var _interface = context.Node as InterfaceDeclarationSyntax; var name = _interface.TryGetInferredMemberName(); if (!(name[0] == 'I' && name.EndsWith("Interface"))) context.ReportDiagnostic(Diagnostic.Create(InterfaceName, context.Node.GetLocation(), name)); } } }
把加入InterfaceAnalyzerContext加入AnalyzerAnalyzer.Contexts里面
public class AnalyzerAnalyzer : DiagnosticAnalyzer { //。。。 private BaseAnalyzContext[] Contexts = new BaseAnalyzContext[] { new InterfaceAnalyzerContext() }; //。。。 }
添加一个项目,添加分析器,选中我们刚才的分析器
我们运行起来看看
在新开的VS里面打开我们刚才的解决方案
打开IService.cs
大功告成
打个广告
欢迎加Q群 386092459 有技术交流或分享,都非常欢迎