如何设计继承IHasInventory的IHasSomeExtendedInventory接口?解决属性冲突
解决接口继承中同名属性的冲突问题
问题场景
定义了IHasInventory接口用于标记类具备Inventory属性;同时有继承自它的IHasSomeExtendedInventory接口,标记类具备功能更丰富的ExtendedInventory(ExtendedInventory继承自Inventory)。但两个接口包含同名的Inventory属性(类型分别为Inventory和ExtendedInventory),导致实现时出现属性冲突。希望找到更简洁的设计方案,明确是否可以仅保留一个Inventory属性,或必须重命名其中一个属性。
原冲突代码:
interface IHasInventory { Inventory Inventory{get;} } interface IHasSomeExtendedInventory : IHasInventory { ExtendedInventory Inventory{get;} } class Inventory { } class ExtendedInventory : Inventory { }
优化方案
方案一:通过接口属性覆盖实现类型协变
你的临时方案可以进一步优化,用new关键字显式覆盖基接口属性,同时用强制转换替代as(避免潜在的null隐患,若实现类返回非ExtendedInventory实例会直接抛出异常,提前发现错误):
interface IHasInventory { Inventory Inventory { get; } } interface IHasSomeExtendedInventory : IHasInventory { new ExtendedInventory Inventory => (ExtendedInventory)base.Inventory; }
实现类只需返回ExtendedInventory实例,即可同时满足两个接口的属性要求:
class Player : IHasSomeExtendedInventory { public ExtendedInventory Inventory { get; } = new ExtendedInventory(); }
方案二:用扩展方法替代接口属性
如果希望接口结构更简洁,可以去掉扩展接口的属性,通过扩展方法提供ExtendedInventory的快捷访问。若仍需要标记类具备扩展库存能力,可保留空标记接口:
interface IHasInventory { Inventory Inventory { get; } } // 空标记接口,仅用于标识类具备ExtendedInventory interface IHasSomeExtendedInventory : IHasInventory { } public static class ExtendedInventoryExtensions { public static ExtendedInventory GetExtendedInventory(this IHasSomeExtendedInventory hasExtInventory) { return (ExtendedInventory)hasExtInventory.Inventory; } }
调用时直接通过扩展方法获取:
var player = new Player(); var extInventory = player.GetExtendedInventory();
方案三:重命名扩展接口属性(最直观无歧义)
如果追求最高的可读性和避免任何潜在混淆,直接重命名扩展接口的属性,实现类只需让两个属性指向同一实例即可:
interface IHasInventory { Inventory Inventory { get; } } interface IHasSomeExtendedInventory : IHasInventory { ExtendedInventory ExtendedInventory { get; } } class Player : IHasSomeExtendedInventory { private readonly ExtendedInventory _inventory = new ExtendedInventory(); public Inventory Inventory => _inventory; public ExtendedInventory ExtendedInventory => _inventory; }
总结
- 若想仅保留一个
Inventory属性,方案一和方案二均可实现,前者通过接口内属性覆盖做类型转换,后者通过扩展方法提供便捷访问; - 若追求无歧义的可读性,方案三的重命名属性是最稳妥的选择。
内容的提问来源于stack exchange,提问作者Mikael Wendt
相关产品推荐
相关产品推荐

