2016-07-28 7 views
0

次のようなクラス階層を考えてみましょう。基本的には、すべてのクラスに共通のフィールドを持つ抽象的なComplexBaseがあります。そして、他のものの間で、またComplexBase由来ComplexElementのコレクションを保持し、ComplexBase由来ComplexClassあります。抽象クラスのC#のリストメンバーを持つクラスの共分散

public abstract class ComplexBase { 
    internal abstract string Identifier { get; } 
} 

public abstract class ComplexClass<T> : ComplexBase where T : ComplexElement { 
    internal SortedList<string, T> Elements { get; set; } 
} 

public abstract class ComplexElement : ComplexBase { } 

実装はComplexClassAComplexClassBです。前者のComplexElementコレクションは、ComplexElementAのインスタンスのみを含み、後者はComplexElementBのインスタンスのみを含みます。私が理解するのに苦労しています何

public class ComplexClassA : ComplexClass<ComplexElementA> { 
    public ComplexClassA() { 
    Elements = new SortedList<string, ComplexElementA>(); 
    } 
} 

public class ComplexElementA : ComplexElement { } 

public class ComplexClassB : ComplexClass<ComplexElementB> { 
    public ComplexClassB() { 
    Elements = new SortedList<string, ComplexElementB>(); 
    } 
} 

public class ComplexElementB : ComplexElement { } 

は、様々なフィールドやメソッドを保持する新しいクラスTheBigCollection、プラスComplexClassAComplexClassB両方のインスタンスのコレクションを定義する方法です。非作業バージョンはComplexClassがジェネリック型で定義されているので、これはコンパイルされません。もちろん、

public class TheBigCollection { 
    internal SortedList<string, ComplexClass> Classes { get; set; } 

    public TheBigCollection() { 
    Classes = new SortedList<string, ComplexClass>(); 
    } 

    public void Add(string name, ComplexClass element) { 
    Classes.Add(name, element); 
    } 
} 

のように見えるかもしれません。

previous attemptは、リストを隠すという概念を使用していたが、それは、これは私がTheBigCollectionのリストから取得ComplexClassAまたはComplexClassBのインスタンスにComplexElementsのリストにアクセスするから私を妨げていることが判明しました。

私は以前の投稿から、共分散が問題を解決できることを知ったが、IEnumerable(これは不変である)を使用してTheBigCollectionのクラスリストの新しい要素を追加する方法を理解できない。

+0

を使用すると、中間クラスComplexClassBaseを作成することを検討しましたか? – michauzo

+0

は@michauzoはい、私は非常に[このポスト](http://www.gamedev.net/topic/660308-list-of-generic-objects/)への回答のラインで、やりました。この解決策で発生する問題は、 'Classes'リストを繰り返し処理することができず、例えば各項目の' Elements.Count'プロパティに、適切なキャストなしでアクセスすることができないことです。 – Informagic

+0

中間クラス(またはインターフェイス)にプロパティを配置することができます。SortedList 要素{get;セット; }次に、特殊タイプを使用してComplexClassで実装します。 – michauzo

答えて

0

私は次のことを試してみました、それが正常に動作します。

internal interface IComplexClass 
{ 
    IDictionary<string, ComplexElement> Elements { get; } 
} 

public abstract class ComplexClass<T> : ComplexBase, IComplexClass where T : ComplexElement 
{ 
    internal SortedList<string, T> Elements { get; set; } 

    IDictionary<string, ComplexElement> IComplexClass.Elements 
    { 
     get { return (IDictionary<string, ComplexElement>)Elements; } 
    } 
} 

これで、TheBigCollectionでIComplexClassを使用することができました。 ComplexBaseとComplexClassBaseからComplexClass を継承:

+0

これはうれしいようです。クラス名を使ってベースクラスのゲッターを上書きすることができるかどうかは分かりませんでしたが、ここでも問題があります。私が 'TheBigColletcion'のインスタンスのクラス 'Classes'についてLinqの問い合わせをしたとします。実行時にクエリ結果の項目の 'Elements'にアクセスすると、' ComplexClassA'sを 'SortedList'を' ComplexClass 'を持つ 'IDictionary'にキャストしようとするため、ゲッターは' System.InvalidCastException'をスローします'es。 – Informagic

+0

計画通りのアクセスを与えないと 'System.InvalidCastException'が' '取得{戻りElements.ToDictionary(EL => el.Key、EL =>(ComplexElementを用いてKeyValuePair'内部キャストを置くものである避けゲッター)el.Value); } '。驚くほど。 – Informagic

+0

確かに。あなたの解決策はそれほどエレガントではありませんが、それは機能しており、これまでのところより良い解決策はありません。 – michauzo