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);
}
The above code gives me a compile error on the dataStore.Add line because it doesn’t like me trying to assign a List<T> to a List<IDataTransferObject>. Since my method restricts T to only IDataTransferObject’s shouldn’t the covariance/contravariance stuff in .Net 4 allow this code?
I know I can change it to do new List<IDataTransferObject> and it will work, but I’m curious why the original code doesn’t work.
Pretty sure a
List<SubClass>isn’t covariant toList<BaseClass>.IEnumerable<T>maybe, but not List as you can freely add a non-T(but stillIDataTransferObjects) which would throw a runtime exception so it’s caught at compile time.While your code might be safe at runtime (as you use keys by type), the compiler doesn’t know this.
What you’re doing would work if you were trying to treat it as
IEnumerable<IDataTransferObject>as those cannot by modified by code (unless you cast it first at which point it would pass/fail if you use a bad type). ButListcan definitely be altered by compile-time code.EDIT: If you don’t mind casting, and really want a
List<T>(so your calling code is typesafe and not adding non-Tobjects once retrieved) you might do something like this:Calling code is like:
So from the outside, all API usage is typesafe. Instead of
ordersbeing aList<IDataTransferObject>(which means you can add non-OrderDTOobjects), it’s strongly typed and cannot be mixed and matched.Of course at this point, there’s no real need to constrain to
IDataTransferObject, but that’s up to you and your API/design/usage.