2013-04-02 2 views
1

У меня есть следующие классы: Почему мой производный класс не переводится в базовый класс?

public class Item 
{ 
} 

public class ItemCollection<TItem> : ICollection<TItem> where TItem : Item, new() 
{ 
} 

у меня есть два производных класса:

public class Feature : Item 
{ 
} 

public class Features : ItemCollection<Feature> 
{ 
} 

У меня есть класс менеджера по управлению такими коллекциями:

public class ItemCollectionManager<TCollection> where TCollection : ItemCollection<Item>, new() 
{ 
} 

Я пытался используйте этот класс:

public class FeatureManager : ItemCollectionManager<Features> 
{ 
} 

, но это приводит к:

«Тип Features должен быть конвертированы в ItemCollection<Item> для того, чтобы использовать его в качестве TCollection в родовом классе ItemCollectionManager<TCollection>».

И, как уже упоминалось ранее,

Features является разновидностью ItemCollection<Feature>

и

Feature является разновидностью Item.

Я не верю, что интерфейсы являются идеальным решением для этой задачи, но я желаю изменить, если причина предоставляется.

Если кто-нибудь может посоветовать, что я делаю неправильно, это будет очень признательно.

спасибо.

ответ

2

Вы не можете сделать ...

ItemCollection<Feature> features = ...; 
ItemCollection<Item> items = features; 

Это о воспроизведенных variance (ковариации и контрвариации, что есть) - и она поддерживается только для интерфейсов, делегатов - и только при условии, что они разработаны таким образом (украшено in/out - и соответствует правилам, которые идут с ним). например IEnumerable<> (если вы найдете его определение, вы увидите out). Для более подробной информации я считаю, что лучше всего читать далее ...

How is Generic Covariance & Contra-variance Implemented in C# 4.0?
Understanding Covariant and Contravariant interfaces in C#
http://msdn.microsoft.com/en-us/library/dd799517.aspx

В вашем случае, вы могли бы разработать IItemCollection<out T> (interface) - что (теоретически ) может поддерживать отвержение вам нужно. Но это должно было быть read-only (tad упрощено и не совсем правильно, но легче думать так - правила немного сложнее).

Поскольку вы называя ее «коллекции» Я предполагаю, что это не только для перечисления, просмотр элементов - то есть, если у вас есть Add этакого (что требует input parameters - т.е. contra-variance), что столкновения с " ковариация "вам нужно для upcasting. Также любые другие связанные параметры могут не позволить вашему интерфейсу быть ковариантным.


Кроме того, некоторые другие должности, которые я сделал, связанные с ...

How to make generic class that contains a Set of only its own type or subtypes as Children?

C# generic handlers, what am I misunderstanding?

+0

+1 для ковариации и ссылок. И я понятия не имел, что вы можете украсить аргументы типа in/out. –

+0

@ MalcolmO'Hare приветствую вас - да, это может быть полезно в определенных сценариях – NSGaga

1

Вам понадобится дополнительный общий аргумент ItemCollectionManager, TItem.

Я считаю, что определение класса ItemCollectionManager должно выглядеть примерно так.

public class ItemCollectionManager<TCollection, TItem> where TCollection : ItemCollection<TItem>, new(), 
where TItem : Item 
    { 
    } 

Путь вы FeatureManager класс, определенный сейчас было бы вполне приемлемо, чтобы добавить любой класс, который наследует Item к TCollection, так как единственное ограничение на TCollection является то, что он содержит классы типа Item. В коллекции Features допускаются только Feature классы или классы, которые наследуют тип Feature. Так как вы не можете добавить базовый тип Item в Features, он не должен компилироваться.

+1

Реализация его таким образом создает дополнительные проблемы вниз по линии, и я не считаю, поставляя TItem необходимо так как это все равно будет «Элементом». Но если это требуется, вы могли бы объяснить немного больше о том, почему? –

+0

Я добавил несколько объяснений. Если это еще не ясно, дайте мне знать, и я попытаюсь объяснить это лучше. –