2
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);
}

List<T>上記のコードでは、にを割り当てようとしているのが気に入らないため、dataStore.Add行でコンパイルエラーが発生しますList<IDataTransferObject>。私のメソッドはTをIDataTransferObjectのみに制限しているので、.Net 4の共分散/反変性のものはこのコードを許可するべきではありませんか?

新しいコードに変更して機能することはわかっていList<IDataTransferObject>ますが、元のコードが機能しない理由がわかります。

4

1 に答える 1

6

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

コードは実行時に安全である可能性がありますが(タイプごとにキーを使用するため)、コンパイラーはこれを認識しません。

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/設計/使用法次第です。

于 2012-10-05T03:31:39.017 に答える