如何实现Hub/IHubDataModel<Sensor>到IHubDataModel<ISensorDataModel>的转换
问题背景
我有如下泛型数据结构:
public interface ISensorDataModel { bool IsHealthy { get; } } public interface ISensor : ISensorDataModel { SensorDataModel GetDataModel(); int StatueCode { get; } void DoSomeWork(); } public interface IHubDataModel<T> where T : ISensorDataModel { List<T>? Sensors { get; } } public interface IHub<T> : IHubDataModel<T> where T : ISensor { bool IsOk { get; } IHubDataModel<T> GetDataModel(); } public class SensorDataModel : ISensorDataModel { public bool IsHealthy { get; set; } } public class Sensor : SensorDataModel, ISensor { public int StatueCode { get; set; } public void DoSomeWork() {} public SensorDataModel GetDataModel() => new SensorDataModel(); } public class HubDataModel<T> : IHubDataModel<T> where T : ISensorDataModel { public List<T>? Sensors { get; set; } public HubDataModel(IHubDataModel<T> other) { Sensors = other.Sensors; } } public class Hub : HubDataModel<Sensor>, IHub<Sensor> { public bool IsOk { get; set; } public IHubDataModel<Sensor> GetDataModel() => new HubDataModel<Sensor>(this); }
我需要完成以下两种转换,但隐式转换无法正常工作:
Hub => IHubDataModel<ISensorDataModel> IHubDataModel<Sensor> => IHubDataModel<ISensorDataModel>
解决方案
问题核心在于泛型接口的协变性:默认情况下IHubDataModel<T>是不变接口,即便Sensor继承自ISensorDataModel,也无法直接实现跨泛型类型的转换。要解决这个问题,需通过以下两种方式处理:
方案1:修改接口为协变类型(推荐)
将IHubDataModel<T>声明为协变接口,同时调整内部成员以符合协变规则:
// 添加out关键字标记T为协变类型参数 public interface IHubDataModel<out T> where T : ISensorDataModel { // 把List<T>改为IEnumerable<T>——因为List<T>是不变类型,而IEnumerable<T>本身是协变的 IEnumerable<T>? Sensors { get; } }
适配实现类
如果业务允许用IEnumerable<T>替代List<T>,直接修改实现类:
public class HubDataModel<T> : IHubDataModel<T> where T : ISensorDataModel { public IEnumerable<T>? Sensors { get; set; } public HubDataModel(IHubDataModel<T> other) { Sensors = other.Sensors; } }
如果必须保留List<T>存储,可以在接口层暴露协变的IEnumerable<T>:
public interface IHubDataModel<out T> where T : ISensorDataModel { IEnumerable<T>? Sensors { get; } } public class HubDataModel<T> : IHubDataModel<T> where T : ISensorDataModel { public List<T>? SensorList { get; set; } public IEnumerable<T>? Sensors => SensorList; public HubDataModel(IHubDataModel<T> other) { if (other is HubDataModel<T> concrete) { SensorList = concrete.SensorList; } else { SensorList = other.Sensors?.ToList(); } } }
修改完成后,隐式转换即可正常工作:
// Hub转IHubDataModel<ISensorDataModel> Hub hub = new Hub(); IHubDataModel<ISensorDataModel> hubDataModel1 = hub; // IHubDataModel<Sensor>转IHubDataModel<ISensorDataModel> IHubDataModel<Sensor> sensorHubData = new HubDataModel<Sensor>(); IHubDataModel<ISensorDataModel> hubDataModel2 = sensorHubData;
方案2:适配器模式(无法修改原接口时使用)
如果原接口是第三方依赖无法修改,可以创建适配器类手动完成转换:
public class HubDataModelAdapter<TFrom, TTo> : IHubDataModel<TTo> where TFrom : TTo, ISensorDataModel where TTo : ISensorDataModel { private readonly IHubDataModel<TFrom> _source; public HubDataModelAdapter(IHubDataModel<TFrom> source) { _source = source; } public List<TTo>? Sensors => _source.Sensors?.Cast<TTo>().ToList(); }
使用示例:
IHubDataModel<Sensor> sensorHubData = new HubDataModel<Sensor>(); IHubDataModel<ISensorDataModel> adapted = new HubDataModelAdapter<Sensor, ISensorDataModel>(sensorHubData);
内容的提问来源于stack exchange,提问作者Reza
相关产品推荐
相关产品推荐

