面试题答案
一键面试- 创建 Roslyn Analyzer 项目:
- 使用 Visual Studio 创建一个新的“代码分析器库”项目。这将为我们提供一个基础结构,用于编写自定义的 Roslyn Analyzer。
- 遍历语法树:
- 在 Analyzer 的
Initialize
方法中注册SyntaxNodeAction
。对于 C#项目,我们主要关注ClassDeclarationSyntax
节点。 - 例如:
context.RegisterSyntaxNodeAction(AnalyzeClass, SyntaxKind.ClassDeclaration);
- 然后在
AnalyzeClass
方法中,获取当前分析的ClassDeclarationSyntax
对象。通过ClassDeclarationSyntax.BaseList
属性检查该类是否继承自特定的抽象类。
private void AnalyzeClass(SyntaxNodeAnalysisContext context) { var classDeclaration = (ClassDeclarationSyntax)context.Node; if (classDeclaration.BaseList!= null) { foreach (var type in classDeclaration.BaseList.Types) { var baseTypeSymbol = context.SemanticModel.GetSymbolInfo(type.Type).Symbol as INamedTypeSymbol; if (baseTypeSymbol!= null && baseTypeSymbol.IsAbstract && baseTypeSymbol.Name == "YourAbstractClassName") { // 找到了继承自特定抽象类的子类 // 开始分析方法重写 } } } }
- 在 Analyzer 的
- 获取抽象类的抽象方法:
- 当确定一个类继承自特定抽象类后,通过
INamedTypeSymbol
获取抽象类的所有抽象方法。
var abstractMethods = baseTypeSymbol.GetMembers().OfType<IMethodSymbol>() .Where(m => m.IsAbstract &&!m.IsStatic);
- 当确定一个类继承自特定抽象类后,通过
- 获取子类的重写方法:
- 在子类的
ClassDeclarationSyntax
中,获取所有的方法声明MethodDeclarationSyntax
。
var subclassMethods = classDeclaration.Members.OfType<MethodDeclarationSyntax>();
- 对于每个
MethodDeclarationSyntax
,通过SemanticModel
获取对应的IMethodSymbol
。
foreach (var method in subclassMethods) { var methodSymbol = context.SemanticModel.GetDeclaredSymbol(method) as IMethodSymbol; if (methodSymbol!= null) { // 处理方法签名比较 } }
- 在子类的
- 比较方法签名:
- 对于抽象类的每个抽象方法和子类的每个方法,比较它们的参数个数和参数类型。
- 参数个数比较:
if (abstractMethod.Parameters.Length!= subclassMethod.Parameters.Length) { // 报告错误,参数个数不一致 context.ReportDiagnostic(Diagnostic.Create(Rule, method.GetLocation(), $"重写方法 {subclassMethod.Identifier.Text} 的参数个数与抽象方法 {abstractMethod.Name} 不一致")); }
- 参数类型比较:
for (int i = 0; i < abstractMethod.Parameters.Length; i++) { if (abstractMethod.Parameters[i].Type.ToDisplayString()!= subclassMethod.Parameters[i].Type.ToDisplayString()) { // 报告错误,参数类型不一致 context.ReportDiagnostic(Diagnostic.Create(Rule, method.GetLocation(), $"重写方法 {subclassMethod.Identifier.Text} 的第 {i + 1} 个参数类型与抽象方法 {abstractMethod.Name} 不一致")); } }
- 报告诊断信息:
- 如果发现子类没有重写抽象类的某个抽象方法,或者重写方法的参数个数或类型不一致,通过
SyntaxNodeAnalysisContext.ReportDiagnostic
方法报告诊断信息。 - 首先需要定义一个
DiagnosticDescriptor
来描述错误规则,例如:
private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( "YourDiagnosticId", "子类必须正确重写抽象类的抽象方法", "子类 {0} 没有正确重写抽象类 {1} 的抽象方法 {2}", "Naming", DiagnosticSeverity.Error, isEnabledByDefault: true);
- 然后在发现问题时调用
context.ReportDiagnostic(Diagnostic.Create(Rule, method.GetLocation(), classDeclaration.Identifier.Text, baseTypeSymbol.Name, abstractMethod.Name));
来报告错误。
- 如果发现子类没有重写抽象类的某个抽象方法,或者重写方法的参数个数或类型不一致,通过