C#重写接口方法使用派生接口参数报错的原因及解决方案
接收接口类型参数的方法支持派生类型实例的方案问题
现有代码定义
首先定义了两层玩家接口,存在继承关系:
public interface IPlayer { public List<Card> LoseCards(); } public interface IPlayer_WithPersonalDeck : IPlayer { public void AddCardsToPersonalDeck(List<Card>); }
在此基础上定义了泛型命令接口,以及面向IPlayer的命令基类:
public interface ICommands<T> { public Object? execute (T); public Object? execute (T, T); } public class BasePlayerCommands : ICommands<IPlayer> { public virtual Object? execute (IPlayer) { throw new NotSupportedException(); } public virtual Object? execute (IPlayer executor, IPlayer target) { throw new NotSupportedException(); } }
编译异常场景
尝试实现特定命令类,完成「从目标玩家处拿牌并加入执行者个人牌组」的逻辑,代码如下:
public class TakeCardsFromPlayer_AndAddToDeckCommand : BasePlayerCommands { public override List<Card> execute(IPlayer_WithPersonalDeck executor, IPlayer target) { return executor.AddCardsToPersonalDeck(target.LoseCards()); } }
上述代码无法通过编译,错误提示为:TakeCardsFromPlayer_AndAddToDeckCommand中找不到可重写的匹配execute方法。
疑问与诉求
报错的直接原因是重写方法时将第一个参数类型写为派生接口IPlayer_WithPersonalDeck而非基接口IPlayer,但按照里氏替换原则,所有实现IPlayer_WithPersonalDeck的类型必然实现了IPlayer接口,要求传入IPlayer的方法理应兼容该派生类型,需要明确该写法不符合预期的底层原因,以及对应的类型安全可行解法。
方案约束:尽量避免直接实现
ICommands<IPlayer_WithPersonalDeck>,因为并非所有玩家命令都要求参与的玩家拥有个人牌组。
当前使用的临时方案是在execute方法内部将IPlayer类型参数强制转换为目标派生接口,但该方案不满足类型安全:任意IPlayer实例都可能被传入,若传入实例未实现对应派生接口会抛出运行时错误,对调用方的约束不足。
内容的提问来源于stack exchange,提问作者Venwin
相关产品推荐
相关产品推荐

