不应协方差/逆变允许这在C#4.5?(Shouldn't Covariance/Contra

2019-09-23 13:28发布

private Dictionary<Type, List<IDataTransferObject>> dataStore = new Dictionary<Type, List<IDataTransferObject>>();

public void Insert<T>(T dto) where T : IDataTransferObject
{
    if (!dataStore.ContainsKey(typeof(T)))
    {
        dataStore.Add(typeof(T), new List<T>());
    }

    dataStore[typeof(T)].Add(dto);
}

上面的代码给我的dataStore.Add行编译错误,因为它不喜欢我试图分配一个List<T>List<IDataTransferObject> 由于我的方法限制吨至仅IDataTransferObject的不应该是.NET 4的协方差/逆变东西,让这个代码?

我知道我可以改变它做新List<IDataTransferObject>它会工作,但我很好奇,为什么原来的代码无法正常工作。

Answer 1:

很肯定一个List<SubClass>不是协变到List<BaseClass>IEnumerable<T>也许,但不是列表,您可以自由添加非T (但仍IDataTransferObjects ),所以它在编译的时候抓住这将引发运行时异常。

当你的代码可能会在运行时的安全(如您使用的密钥按类型),编译器不知道这一点。

List<Animal> animalList = new List<Animal>();
animalList.Add(new Dog()); //ok!

List<Cat> catList = new List<Cat>();
animalList = catList; //Compiler error: not allowed, but it's what you're trying to do
animalList.Add(new Dog()) //Bad stuff! Trying to add a Dog to a List<Cat>

你正在做的,如果你试图把它当作会工作什么IEnumerable<IDataTransferObject>那些无法通过代码修改(除非你先投它在这一点,它会通过/如果你使用一个坏的类型失败)。 但List绝对可以通过编译时的代码被改变。

编辑:如果你不介意的铸造,真想一List<T>所以你调用的代码是类型安全的,并且不添加非T对象检索一次),你可能做这样的事情:

private Dictionary<Type, object> dataStore = new Dictionary<Type, object>();

public void Insert<T>(T dto) where T : IDataTransferObject
{
    object data;
    if (!dataStore.TryGetValue(typeof(T), out data))
    {
        var typedData = new List<T>();
        dataStore.Add(typeof(T), typedData);
        typedData.Add(dto);
    }
    else
    {
        ((List<T>)data).Add(dto);
    }
}


//you didn't provide a "getter" in your sample, so here's a basic one
public List<T> Get<T>() where T : IDataTransferObject
{
    object data;
    dataStore.TryGetValue(typeof(T), out data);
    return (List<T>)data;
}

调用代码如下:

Insert(new PersonDTO());
Insert(new OrderDTO());
Insert(new PersonDTO());

List<PersonDTO> persons = Get<PersonDTO>();
List<OrderDTO> orders = Get<OrderDTO>();

Console.WriteLine(persons.Count); //2
Console.WriteLine(orders.Count); //1

所以从外面看,所有的API使用类型安全是。 相反的orders是一个List<IDataTransferObject>这意味着你可以添加非OrderDTO对象),它是强类型的,不能混用并匹配。

当然,在这一点上,没有真正的必要限制,以IDataTransferObject ,但是这取决于你和你的API /设计/使用。



文章来源: Shouldn't Covariance/Contravariance allow this in C# 4.5?