2016-07-28 27 views
0

考慮如下所示的類層次結構。實質上,有一個抽象的ComplexBase,其中有一些對所有類都通用的字段。然後從ComplexBase導出ComplexClass,除此之外,持有也來自ComplexBaseComplexElement的集合。抽象類的在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的實例的集合。非工作版本可能看起來像

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

當然,這不會編譯因爲ComplexClass與泛型類型定義。

previous attempt是使用隱藏列表的概念,但事實證明,這使我訪問中,我從TheBigCollection列表檢索ComplexClassAComplexClassB實例ComplexElements名單。

我從我以前的帖子中瞭解到協變可以解決問題,但我不明白如何使用IEnumerable - 這是不可變的 - 可以用來添加新元素到TheBigCollection的類列表。

+0

您是否考慮創建一箇中間類ComplexClassBase:ComplexBase並從ComplexClassBase繼承ComplexClass ? – michauzo

+0

@michauzo是的,我做了,非常符合[本文]的答案(http://www.gamedev.net/topic/660308-list-of-generic-objects/)。這個解決方案出現的問題是,我無法遍歷列表'Classes'並訪問,例如,每個項目的'Elements.Count'屬性不再適當的強制轉換。 – Informagic

+0

在中間類(或接口)中,你可以把屬性SortedList Elements {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了。

+0

這看起來很不錯 - 我不知道用類名引用它可以覆蓋基類的getter,但這裏也有問題。想象一下,我對'TheBigColletcion'實例的成員'Classes'有一個Linq查詢。在運行時訪問查詢結果的元素的'元素'時,getter會拋出一個'System.InvalidCastException',因爲它試圖用'ComplexClass'將'SortedList'與例如'ComplexClassA'一起強制轉換爲'IDictionary' '上課。 – Informagic

+0

確實按計劃授予訪問權並且避免「System.InvalidCastException」的getter是通過使用get {return Elements.ToDictionary(el => el.Key,el =>(ComplexElement)將演員放入「KeyValuePair」 )el.Value); }'。驚人。 – Informagic

+0

確實。您的解決方案是不是很優雅,但它的作品,我看不出有什麼更好的那麼遠。 – michauzo

相關問題