Covariance / Contravariance不应该在C#4.5中允许这样吗?

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

上面的代码给出了dataStore.Add行的编译错误,因为它不喜欢我尝试将List分配给List 。 由于我的方法将T限制为只有IDataTransferObject,因此.Net 4中的协方差/反函数不应该允许这个代码吗?

我知道我可以改变它来做新的List它会工作,但我很好奇为什么原始代码不起作用。

很确定ListList不协变。 IEnumerable可能,但不是List,因为你可以自由地添加一个非T (但仍然是IDataTransferObjects ),它会抛出运行时exception,因此它在编译时被捕获。

虽然您的代码在运行时可能是安全的(因为您按类型使用键),但编译器不知道这一点。

 List animalList = new List(); animalList.Add(new Dog()); //ok! List catList = new List(); 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 

如果您尝试将其视为IEnumerable ,那么您所做的工作将会起作用,因为这些不能通过代码修改(除非您先将其IEnumerable转换,否则如果您使用错误类型则会通过/失败)。 但List绝对可以通过编译时代码进行更改。

编辑:如果你不介意转换,并且真的想要一个List (所以你的调用代码是类型安全的,一旦检索不添加非T对象)你可能会这样做:

 private Dictionary dataStore = new Dictionary(); public void Insert(T dto) where T : IDataTransferObject { object data; if (!dataStore.TryGetValue(typeof(T), out data)) { var typedData = new List(); dataStore.Add(typeof(T), typedData); typedData.Add(dto); } else { ((List)data).Add(dto); } } //you didn't provide a "getter" in your sample, so here's a basic one public List Get() where T : IDataTransferObject { object data; dataStore.TryGetValue(typeof(T), out data); return (List)data; } 

调用代码就像:

 Insert(new PersonDTO()); Insert(new OrderDTO()); Insert(new PersonDTO()); List persons = Get(); List orders = Get(); Console.WriteLine(persons.Count); //2 Console.WriteLine(orders.Count); //1 

因此,从外部来看,所有API使用都是类型安全的。 而不是ordersList (这意味着您可以添加非OrderDTO对象),它是强类型的,不能混合和匹配。

当然,在这一点上,并没有真正需要约束到IDataTransferObject ,但这取决于您和您的API /设计/用法。