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
它会工作,但我很好奇为什么原始代码不起作用。
很确定List
与List
不协变。 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使用都是类型安全的。 而不是orders
是List
(这意味着您可以添加非OrderDTO
对象),它是强类型的,不能混合和匹配。
当然,在这一点上,并没有真正需要约束到IDataTransferObject
,但这取决于您和您的API /设计/用法。