如何在编译期强制重写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
相关产品推荐
相关产品推荐

