C#子类重写方法时签名不匹配的正确解决方式
编译期保证类型安全的解决方案
核心思路是通过泛型约束在编译阶段绑定Action与对应的EventArgs类型,彻底避免运行时类型检查的不确定性。
方案一:泛型基类直接约束(适用于无需跨类型多态的场景)
重构基类为泛型类,指定EventArgs的类型约束,子类继承时明确具体的EventArgs类型:
public class ActionEventArgs : EventArgs { public Creature actor; } public class LocationEventArgs : ActionEventArgs { public Location loc; } // 泛型基类,约束TEventArgs必须继承自ActionEventArgs public abstract class Action<TEventArgs> where TEventArgs : ActionEventArgs { public abstract void Do(object sender, TEventArgs e); } // 子类直接绑定LocationEventArgs,重写方法签名完全匹配 public class LocationAction : Action<LocationEventArgs> { public override void Do(object sender, LocationEventArgs e) { // 直接使用e.loc,编译阶段已保证类型正确 // ... 业务逻辑实现 } } public class MainClass { // 直接声明为具体的泛型类型,编译期约束类型匹配 public Action<LocationEventArgs> a { get; protected set; } public void InitAction() { a = new LocationAction(); } public void DoAction(Creature actor, Location location) { a.Do(this, new LocationEventArgs() { actor = actor, loc = location }); } }
方案二:泛型+非泛型接口(支持多态场景)
如果需要在MainClass中兼容多种Action类型(多态),可以先定义非泛型接口,再让泛型基类实现该接口,通过显式接口实现完成类型转换(泛型约束保证转换安全):
public class ActionEventArgs : EventArgs { public Creature actor; } public class LocationEventArgs : ActionEventArgs { public Location loc; } // 非泛型接口,用于多态场景 public interface IAction { void Do(object sender, ActionEventArgs e); } // 泛型基类,实现IAction并约束EventArgs类型 public abstract class Action<TEventArgs> : IAction where TEventArgs : ActionEventArgs { // 子类重写此方法,直接使用具体的TEventArgs类型 public abstract void Do(object sender, TEventArgs e); // 显式实现接口,完成类型转换(泛型约束保证转换安全) void IAction.Do(object sender, ActionEventArgs e) { Do(sender, (TEventArgs)e); } } public class LocationAction : Action<LocationEventArgs> { public override void Do(object sender, LocationEventArgs e) { // 编译期确保e是LocationEventArgs,可直接访问loc属性 // ... 业务逻辑实现 } } public class MainClass { // 使用非泛型接口实现多态 public IAction a { get; protected set; } public void InitAction() { a = new LocationAction(); } public void DoAction(Creature actor, Location location) { // 此处传入明确的LocationEventArgs,与Action类型匹配 a.Do(this, new LocationEventArgs() { actor = actor, loc = location }); } }
方案说明
- 泛型约束确保了Action子类只能绑定指定的EventArgs类型,编译阶段就能检测到类型不匹配的错误,无需依赖运行时检查。
- 方案二通过非泛型接口保留了多态能力,同时利用泛型约束保证了类型转换的安全性,避免了无效转换的风险。
内容的提问来源于stack exchange,提问作者Илья Кротов
相关产品推荐
相关产品推荐

