C#中无需手动调用基类即可自动扩展方法实现统一日志记录的方案
解决基类预置逻辑被派生类重写覆盖不触发的问题
这个场景的核心问题是:C#中派生类重写虚方法时,如果不手动调用base.xxx(),基类的原有逻辑会被直接跳过。要实现基类通用逻辑强制自动执行、不需要派生类手动维护调用,最稳妥的方案是采用模板方法模式重构类结构。
实现思路
把原来带通用日志逻辑的对外入口方法(Start、Update、End)设为非虚的封闭方法,禁止派生类直接重写整个流程。在入口方法内部按固定顺序执行:
- 先跑基类预置的统一日志逻辑
- 再调用专门留给派生类实现业务的
protected钩子方法
从结构上保证:只要外部调用入口方法,基类的日志逻辑一定会执行,完全不依赖派生类手动写base调用。
重构后的代码
using System; public abstract class Phase { // 对外暴露的统一入口,禁止派生类重写完整流程 public void Start() { // 基类统一日志,无条件先执行 Console.Write("[LOG] Start"); // 调用派生类的业务实现 OnStart(); } /// <summary> /// Returns true when finished. /// </summary> public bool Update() { // 基类统一日志 Console.Write("[LOG] Update"); // 把派生类的业务返回值透传出去 return OnUpdate(); } public void End() { // 基类统一日志 Console.Write("[LOG] End"); // 调用派生类的业务实现 OnEnd(); } // 给派生类留的业务实现钩子,仅内部可访问 protected virtual void OnStart() { } protected virtual bool OnUpdate() => true; protected virtual void OnEnd() { } } public class PhaseMenu : Phase { private byte _counter; // 派生类只需要重写业务钩子,完全不需要关心日志逻辑 protected override void OnStart() { _counter = 0; } protected override bool OnUpdate() { _counter++; if ( _counter > 100 ) { return true; } return false; } protected override void OnEnd() { // 派生类自定义的End逻辑,留空也不会影响基类日志执行 } }
实际效果
- 所有派生类调用对外的
Start/Update/End方法时,基类的日志逻辑会自动触发,不存在漏执行的可能 - 派生类开发者只需要聚焦自身业务逻辑,不需要记忆、手动添加
base.xxx()的调用,从代码结构上避免了漏写导致的逻辑丢失 - 后续如果需要给所有Phase子类增加统一的前置/后置逻辑(比如异常捕获、耗时统计),只需要修改基类的入口方法即可,所有派生类自动生效
针对个别需要临时跳过日志的特殊派生类,可以在基类增加可配置的布尔开关,在入口方法判断开关状态决定是否输出日志,不需要破坏整体的结构约束。
内容的提问来源于stack exchange,提问作者Dorjan
相关产品推荐
相关产品推荐

