You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否标记即将变为抽象的.NET虚成员以触发编译器警告?

在.NET中实现标记未来抽象成员的子类警告机制

咱们都知道.NET里的ObsoleteAttribute能标记要移除的成员或类型,触发编译器警告612/618。现在需要一个类似的[SoonToBeAbstract]特性:标记当前是虚成员、未来要改成抽象的方法/属性,要求编译器给没重写该成员的子类发警告,避免以后成员变抽象后子类直接编译失败,而且不想自己手动写代码遍历继承链。

期望的效果示例:

public class MyBaseClass
{
  [SoonToBeAbstract] // 自定义特性
  public virtual void DoSomething() {}
}

public class MySubClass : MyBaseClass // 这里该出警告:没重写即将变抽象的DoSomething
{
}

实现方案

.NET原生没有内置这个检查逻辑,最靠谱的方式是用Roslyn代码分析器来做——而且Roslyn的API已经封装了继承链遍历的逻辑,不用咱们自己手动写递归或者遍历代码:

1. 先定义自定义特性

这个特性只是个标记,用来让分析器识别目标成员:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false)]
public class SoonToBeAbstractAttribute : Attribute
{
    // 不需要额外逻辑,纯标记用
}

2. 编写Roslyn分析器核心逻辑

分析器要做的就是:找到被[SoonToBeAbstract]标记的基类虚成员,然后检查所有子类有没有重写它,没重写就发警告。

核心代码片段(已经利用Roslyn内置的继承链和成员匹配逻辑):

public override void Initialize(AnalysisContext context)
{
    context.EnableConcurrentExecution();
    context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

    // 注册类型分析的回调
    context.RegisterSymbolAction(AnalyzeType, SymbolKind.NamedType);
}

private void AnalyzeType(SymbolAnalysisContext context)
{
    var typeSymbol = (INamedTypeSymbol)context.Symbol;

    // 遍历当前类型的所有基类(Roslyn的GetBaseTypesAndThis帮我们处理了继承链)
    foreach (var baseType in typeSymbol.BaseType.GetBaseTypesAndThis())
    {
        // 找基类里被SoonToBeAbstract标记的虚成员
        foreach (var member in baseType.GetMembers())
        {
            if (member is IMethodSymbol method && method.IsVirtual 
                && method.GetAttributes().Any(attr => attr.AttributeClass.Name == nameof(SoonToBeAbstractAttribute)))
            {
                // 检查当前子类有没有重写这个方法
                var hasOverride = typeSymbol.GetMembers(method.Name)
                    .OfType<IMethodSymbol>()
                    .Any(m => m.IsOverride && m.OverriddenMethod.Equals(method, SymbolEqualityComparer.Default));

                if (!hasOverride)
                {
                    // 发出警告
                    context.ReportDiagnostic(Diagnostic.Create(
                        Descriptors.SoonToBeAbstractWarning,
                        typeSymbol.Locations[0],
                        typeSymbol.Name,
                        method.Name));
                }
            }
            // 如需支持属性,可添加类似的IPropertySymbol判断逻辑
        }
    }
}

3. 定义诊断规则

指定警告的ID、提示消息等:

private static class Descriptors
{
    public static readonly DiagnosticDescriptor SoonToBeAbstractWarning = new(
        id: "STA001",
        title: "未重写即将抽象的成员",
        messageFormat: "类型 '{0}' 未重写基类中即将变为抽象的成员 '{1}'",
        category: "Design",
        defaultSeverity: DiagnosticSeverity.Warning,
        isEnabledByDefault: true,
        description: "该成员未来会改为抽象,子类必须重写以避免后续编译失败。");
}

说明

这个方案完全不需要手动实现继承链遍历——Roslyn的GetBaseTypesAndThis()方法已经帮我们遍历了所有基类,IsOverride和OverriddenMethod属性也直接帮我们判断了子类是否重写了目标成员,逻辑简洁且可靠。

内容的提问来源于stack exchange,提问作者F-H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:20:59