2009-09-08 4 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 должен иметь безпараметрический конструктор. И призывный призыв не считает, что ItemCollection происходит от CollectionBase<ItemBase>.

Может кто-нибудь указать мне в правильном направлении? Благодарю.

ответ

6

ItemCollectionне является, полученным из CollectionBase<ItemBase>, из-за общей инвариантности. В конце концов, вы можете добавить ItemBase в CollectionBase<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 '. Читайте в блоге блога Эрика Липперта о разбросе для более подробной информации - к сожалению, мне нужно бежать сейчас, так что не успевайте загнать ссылку. –

3

Проблемы здесь общие ограничения, в C# 3.0, есть какие-либо свобода действий в отношении дисперсии. Соответствие является довольно строгим. Поскольку ItemCollection происходит от CollectionBase<Item>, он не считается производным от CollectionBase<ItemBase>, хотя типы могут отображаться для совместимости.