Почти уверен, что 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>
(поэтому ваш вызывающий код является типобезопасным и не добавляет не-10_ объекты после извлечения), вы можете сделать что-то вроде этого:
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/дизайна/использования.
person
Chris Sinclair
schedule
05.10.2012
IReadOnlyList<out T>
интерфейс, который является ковариантным в своемT
. Обратите внимание, что в .NET ковариантными могут быть только интерфейсы (и типы делегатов), а не классы/структуры. Причина, по которойIReadOnlyList<>
может быть сделана ковариантной, заключается в том, что она включает только элементы, которые читают из базового списка (не записывают). ОднакоIReadOnlyList<>
не поможет вам в вашей невозможной проблеме, так что .NET 4.5 здесь, в конце концов, не поможет. - person Jeppe Stig Nielsen   schedule 27.11.2012