List<SubClass>
は、と共変ではないことを確認してList<BaseClass>
ください。たぶん、しかしリストではありません。コンパイル時にキャッチされるようにランタイム例外をスローする非(ただしそれでも)をIEnumerable<T>
自由に追加できるからです。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/設計/使用法次第です。