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>
。由于我的方法将T限制为只有IDataTransferObject,因此.Net 4中的协方差/逆变量不应该允许此代码吗?
我知道我可以将其更改为新的List<IDataTransferObject>
并且它会起作用,但我很好奇为什么原始代码不起作用。
答案 0 :(得分:6)
非常确定List<SubClass>
与List<BaseClass>
不一致。 IEnumerable<T>
可能,但不是List,因为你可以自由地添加一个非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 /设计/用途。