如何为特定IVehicle实现强制指定对应的ITrackInfo特定实现?
问题描述
现有如下接口定义:
public interface IVehicle { ITrackInfo TrackInfo { get; set; } void ShowInfo(); } public interface ITrackInfo { int Length { get; set; } }
以及ITrackInfo的三个实现类:
public class RailInfo : ITrackInfo { public int Length { get; set;} public int SleeperSpacing { get; set; } } public class CanalInfo : ITrackInfo { public int Length { get; set; } public decimal AverageDepth { get; set; } } public class RoadInfo : ITrackInfo { public int Length { get; set; } public Color Colour { get; set; } }
希望为每个IVehicle的实现类绑定对应的ITrackInfo特定实现(比如Train对应RailInfo、Boat对应CanalInfo),但直接按如下写法会编译失败——因为IVehicle要求TrackInfo必须是ITrackInfo类型:
public class Train : IVehicle { public RailInfo TrackInfo { get; set; } public void ShowInfo() { Console.WriteLine("Railway is {0}km long", TrackInfo.Length.ToString()); Console.WriteLine("Distance between sleepers is {0}cm", TrackInfo.SleeperSpacing); } } public class Boat : IVehicle { public CanalInfo TrackInfo { get; set; } public void ShowInfo() { Console.WriteLine("Canal is {0}km long", TrackInfo.Length.ToString()); Console.WriteLine("The average depth is {0}m", TrackInfo.AverageDepth.ToString("F2")); } } public class Bus : IVehicle { public RoadInfo TrackInfo { get; set; } public void ShowInfo() { Console.WriteLine("Road is {0}km long", TrackInfo.Length.ToString()); Console.WriteLine("The road is coloured {0}", TrackInfo.Colour.ToString()); } }
不想用ShowInfo里做类型检查这种不够优雅的方案:
var info = TrackInfo as RailInfo; if (info == null) { throw new Exception("Incorrect track info"); }
需求是找到一种能为特定IVehicle实现强制绑定对应ITrackInfo特定实现的优雅方式。
优雅解决方案:泛型接口约束
通过将IVehicle修改为泛型接口,并对泛型参数添加类型约束,就能在编译阶段确保每个车辆类绑定对应的轨道信息类型,完全避免运行时类型检查。
步骤1:修改IVehicle为泛型接口
public interface IVehicle<TTrackInfo> where TTrackInfo : ITrackInfo { TTrackInfo TrackInfo { get; set; } void ShowInfo(); }
这里通过where TTrackInfo : ITrackInfo约束泛型参数必须实现ITrackInfo接口,保证类型合法性。
步骤2:修改车辆实现类
每个车辆类实现对应的泛型接口版本,指定具体的TTrackInfo类型:
public class Train : IVehicle<RailInfo> { public RailInfo TrackInfo { get; set; } public void ShowInfo() { Console.WriteLine("Railway is {0}km long", TrackInfo.Length.ToString()); Console.WriteLine("Distance between sleepers is {0}cm", TrackInfo.SleeperSpacing); } } public class Boat : IVehicle<CanalInfo> { public CanalInfo TrackInfo { get; set; } public void ShowInfo() { Console.WriteLine("Canal is {0}km long", TrackInfo.Length.ToString()); Console.WriteLine("The average depth is {0}m", TrackInfo.AverageDepth.ToString("F2")); } } public class Bus : IVehicle<RoadInfo> { public RoadInfo TrackInfo { get; set; } public void ShowInfo() { Console.WriteLine("Road is {0}km long", TrackInfo.Length.ToString()); Console.WriteLine("The road is coloured {0}", TrackInfo.Colour.ToString()); } }
方案优势
- 编译时类型安全:如果给
Train赋值非RailInfo类型的轨道信息,编译阶段直接报错,提前规避错误 - 代码简洁:无需类型转换和空值检查,直接使用特定类型的属性和方法
- 扩展性强:新增车辆类型和对应的轨道信息类型时,只需实现对应泛型接口即可,符合开闭原则
内容的提问来源于stack exchange,提问作者komodosp
相关产品推荐
相关产品推荐

