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

如何在编译期强制重写foo类的至少一个或恰好一个虚方法?

如何强制子类至少/恰好重写指定的其中一个虚方法?

先明确我们的基础代码(修正了原代码里的语法小问题):

基类foo:

public class foo{
    internal virtual object M1(/*args*/){return null;}
    internal virtual object[] M2(/*args*/){return null;}
    public SomeStruct SomeMethod(){
        return new SomeStruct { Obj = M1(), ObjArr = M2() };
    }
}

结构体SomeStruct:

public struct SomeStruct {
    public object Obj;
    public object[] ObjArr;
}

你的需求是:有没有办法(最好在编译阶段)强制foo的子类至少重写一个方法,或恰好重写一个方法?而且不想用单一方法通过返回类型判断赋值的方案,希望保留原有M1、M2的设计。


编译阶段的最优方案:自定义Roslyn分析器

C#本身没有原生语法支持直接约束子类必须重写指定虚方法中的一个(或恰好一个),但自定义Roslyn代码分析器可以实现编译期的强制检查,这是最贴合你需求的方案:

1. 强制子类至少重写一个方法

你可以编写一个Roslyn分析器,逻辑如下:

  • 扫描所有继承自foo的类
  • 检查每个子类是否重写了M1或M2(通过语法节点判断方法带有override修饰符,且签名与基类方法匹配)
  • 如果子类两个方法都没重写,直接抛出编译错误或警告

这种方式完全在编译阶段生效,不会对运行时性能有任何影响,完美保留你原有方法的设计。

2. 强制子类恰好重写一个方法

只需要把分析器的判断逻辑调整为:统计子类重写M1和M2的数量,若数量不等于1,则触发编译错误。

运行时的简易替代方案

如果暂时不想开发自定义分析器,也可以在基类中通过反射做运行时检查,虽然不能在编译期发现问题,但能在子类实例化时快速报错:

1. 确保至少重写一个方法

修改基类的构造函数:

public class foo{
    internal virtual object M1(/*args*/){return null;}
    internal virtual object[] M2(/*args*/){return null;}
    
    protected foo()
    {
        var currentType = GetType();
        // 判断当前类型是否重写了M1或M2
        var overridesM1 = currentType.GetMethod(nameof(M1), BindingFlags.Instance | BindingFlags.NonPublic)?.DeclaringType == currentType;
        var overridesM2 = currentType.GetMethod(nameof(M2), BindingFlags.Instance | BindingFlags.NonPublic)?.DeclaringType == currentType;
        
        if (!overridesM1 && !overridesM2)
        {
            throw new InvalidOperationException("子类必须重写M1或M2中的一个方法");
        }
    }

    public SomeStruct SomeMethod(){
        return new SomeStruct { Obj = M1(), ObjArr = M2() };
    }
}

2. 确保恰好重写一个方法

把构造函数里的判断逻辑改成:

if ((overridesM1 && overridesM2) || (!overridesM1 && !overridesM2))
{
    throw new InvalidOperationException("子类必须恰好重写M1或M2中的一个方法");
}

这种方案不需要额外开发工具,实现简单,但缺点是只有在实例化子类时才会暴露问题,无法提前在编译阶段发现。

总结

如果一定要编译阶段的强制约束,自定义Roslyn分析器是唯一可行的方案;如果可以接受运行时检查,基类构造函数的反射判断就能快速满足需求。两种方案都不需要修改你原有M1、M2和SomeMethod的逻辑,完全符合你的要求。


内容的提问来源于stack exchange,提问作者Miku

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:01:11