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 有技術交流或分享,都非常歡迎