You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 23:30:56