如何在C#中限制对象匹配特定实现接口进行类型检测?
问题解答
1. 为什么z_objMotorBoat is ISailBoat返回true?
C#的is运算符判断的是对象的实际运行时类型是否实现了目标接口/类,而非变量的声明类型。
你的z_objMotorBoat变量虽然声明为IMotorBoat,但它指向的实例是GenericBoat类型。而GenericBoat实现了IGenericBoat接口,IGenericBoat又同时继承了ISailBoat和IMotorBoat,所以这个实例本质上同时是两个接口的实现者。因此,无论用哪个接口的变量去引用它,is ISailBoat都会返回true。
1a. 核心原因
就是因为z_objMotorBoat的实例是GenericBoat,它通过IGenericBoat间接实现了ISailBoat接口,运行时类型检查只会看实例本身的实现,和变量的声明类型无关。
2. 如何正确区分ISailBoat和IMotorBoat类型的对象?
由于GenericBoat同时实现了两个接口,单纯靠接口类型检查无法区分。以下是两种无需创建独立类的可行方案:
方案1:添加类型标识属性
在基础接口中定义枚举类型的标识,让实现类明确自身的类型:
// 定义船的类型枚举 public enum BoatCategory { SailBoat, MotorBoat } // 修改基础接口,添加类型标识 public interface IBasicBoat { Hull BoatHull { get; set; } BoatCategory Category { get; } } // 实现类通过构造函数指定类型 public class GenericBoat : IGenericBoat { public Hull BoatHull { get; set; } public List<Sail> Sails { get; set; } public Engine Motor { get; set; } public BoatCategory Category { get; } public GenericBoat(BoatCategory category) { Category = category; } }
创建对象时指定类型:
ISailBoat z_objSailBoat = new GenericBoat(BoatCategory.SailBoat) { BoatHull = new Hull(), Sails = new List<Sail>() }; IMotorBoat z_objMotorBoat = new GenericBoat(BoatCategory.MotorBoat) { BoatHull = new Hull(), Motor = new Engine() };
在CheckBuoyancy中判断:
public void CheckBuoyancy(IBasicBoat p_objBoat) { if (p_objBoat.Category == BoatCategory.SailBoat && p_objBoat is ISailBoat sailBoat) { // 执行帆船专属逻辑,比如检查sailBoat.Sails } else if (p_objBoat.Category == BoatCategory.MotorBoat && p_objBoat is IMotorBoat motorBoat) { // 执行摩托艇专属逻辑,比如检查motorBoat.Motor } }
方案2:检查接口成员的有效性
如果业务规则中,帆船必须初始化Sails,摩托艇必须初始化Motor,可以通过检查成员状态来区分:
public void CheckBuoyancy(IBasicBoat p_objBoat) { // 仅当是帆船且Sails已初始化时执行逻辑 if (p_objBoat is ISailBoat sailBoat && sailBoat.Sails != null) { // 处理帆船的帆检查逻辑 } // 仅当是摩托艇且Motor已初始化时执行逻辑 if (p_objBoat is IMotorBoat motorBoat && motorBoat.Motor != null) { // 处理摩托艇的发动机检查逻辑 } }
这种方案无需修改现有接口和类,但依赖对象初始化时的成员状态,适合业务规则明确的场景。
内容的提问来源于stack exchange,提问作者Jean-David Lanz
相关产品推荐
相关产品推荐

