2009-09-08 101 views
2

我想寫一個工廠方法,將創建一個抽象泛型集合類的派生實例。以下是基類...C# - 如何從工廠方法創建一個繼承的泛型集合

abstract class ItemBase { } 

abstract class CollectionBase<T> : Collection<T> where T : ItemBase, new() { } 

...及其派生類...

class Item : ItemBase { } 

class ItemCollection : CollectionBase<Item> {} 

現在,我希望有一個工廠方法,將創建一個ItemCollection。但請注意,派生類Item和ItemCollection對於包含此工廠方法的類是未知的。這是我想它應該是...

static T CreateItemCollection<T>() where T : CollectionBase<ItemBase>, new() 
{ 
    return new T(); 
} 

...和我想象這樣調用它...

var collection = CreateItemCollection<ItemCollection>(); 

但工廠方法不會編譯,因爲ItemBase必須有無參數構造函數。並且invokeation調用拒絕相信ItemCollection源自CollectionBase<ItemBase>

有人可以請指出我在正確的方向嗎?謝謝。

回答

6

ItemCollection不是CollectionBase<ItemBase>派生,由於泛型不變性。畢竟,你可以添加一個ItemBaseCollectionBase<ItemBase> - 但你不想爲你的ItemCollection

你需要讓通用的方法有兩種類型的參數:

static T CreateItemCollection<TCollection, TItem>() 
    where TCollection : CollectionBase<TItem>, new() 
    where TItem : ItemBase 
{ 
    return new TCollection(); 
} 

只有集合類型需要一個參數的構造函數。你可以這樣稱呼:

var collection = CreateItemCollection<ItemCollection, Item>(); 
+0

謝謝。這解決了我的問題,即使我仍然不能完全理解編譯器堅持如此嚴格的原因(如下面的JaredPar所述)。 –

+1

@Tim:正如我所說的,因爲'ItemCollection' *不能*允許所有與'CollectionBase '相同的調用。閱讀Eric Lippert關於差異的博客系列,瞭解更多細節 - 不幸的是我需要現在運行,所以沒有時間去追逐鏈接。 –

3

這裏的問題是C#3.0中的通用約束在方差方面有任何餘地。匹配反而相當嚴格。由於ItemCollection來自CollectionBase<Item>,因此它不被認爲是從CollectionBase<ItemBase>派生的,即使類型可能出現爲兼容。