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