此分析器功能比较简陋,仅作个人备忘。
参考资料:https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/tutorials/how-to-write-csharp-analyzer-code-fix
将以下分析器代码编译为DLL后,将DLL添加到项目分析器列表中,即可进行相关分析。
分析器代码:
using System;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;namespace DontCallBaseImplementation
{[AttributeUsage(AttributeTargets.Method, Inherited = false)]public class DontCallBaseImplementationAttribute : Attribute { }[DiagnosticAnalyzer(LanguageNames.CSharp)]public class DontCallBaseImplementationAnalyzer : DiagnosticAnalyzer{public const string DiagnosticId = "DontCallBaseImplementation";private static readonly LocalizableString Title = "Invalid base method implementation call";private static readonly LocalizableString MessageFormat = "Method '{0}' with [DontCallBaseImplementationAttribute] should not call base method implementation";private static readonly LocalizableString Description = "The method in the derived class calls the base method implementation which is marked with [DontCallBaseImplementationAttribute].";private const string Category = "Usage";private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category,DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }public override void Initialize(AnalysisContext context){context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);context.EnableConcurrentExecution();context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.InvocationExpression);}private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context){InvocationExpressionSyntax invocationExpression = (InvocationExpressionSyntax)context.Node;if (invocationExpression.Expression is MemberAccessExpressionSyntax memberAccess &&memberAccess.Expression is BaseExpressionSyntax){IMethodSymbol invokedSymbol = context.SemanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol;if (invokedSymbol == null) return;IMethodSymbol currentMethod = context.ContainingSymbol as IMethodSymbol;IMethodSymbol baseMethod = currentMethod?.OverriddenMethod;if (!SymbolEqualityComparer.Default.Equals(invokedSymbol, baseMethod)) return;AttributeData dontCallBaseImplAttr = baseMethod.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.Name == nameof(DontCallBaseImplementationAttribute));if (dontCallBaseImplAttr != null){Diagnostic diagnostic = Diagnostic.Create(Rule, invocationExpression.GetLocation(), memberAccess.Name);context.ReportDiagnostic(diagnostic);}}}}
}
添加分析器:
在项目的配置文件(csproj)中,添加 ItemGroup
指定分析器引用:
< !--Add to YOUR_PROJECT.csproj-- >
< Project Sdk = "Microsoft.NET.Sdk" >< !--... -->< ItemGroup >< Analyzer Include = "ABSOLUTE_OR_RELATIVE_FOLDER\DontCallBaseImplementation.dll" /></ ItemGroup >< !--... --></ Project >
代码中的使用方法:
定义一个 DontCallBaseImplementationAttribute
类(也可以直接使用分析器DLL中提供的同名类,但要为项目添加对DLL的依赖项):
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class DontCallBaseImplementationAttribute : Attribute { }
在不希望子类覆写时调用父类方法实现的虚方法上,添加上述特性:
class BaseClass
{[DontCallBaseImplementation]public virtual void DoSomething(){Console.WriteLine("BaseClass.DoSomething()");}
}
之后,若子类重写方法时调用了父类方法实现,编辑器会报告错误:
class DerivedClass : BaseClass
{public override void DoSomething(){base.DoSomething(); // Will report an error}
}