ОК, так вот ситуация. У меня есть класс FlexCollection<T>
, целью которого является сохранение списка некоторой специализации FlexItem
, поэтому:
public class FlexCollection<T> where T : FlexItem, new()
{
public void Add(T item) { ... }
...
}
FlexItem
не является общим классом. То, что я хотел достичь, - это способность удерживать в поле FlexItem
ссылку на коллекцию, содержащую объект. К сожалению, в С# невозможно провести ссылку на "любую" специализацию класса шаблона (как в Java). Сначала я попытался использовать не-общий интерфейс IFlexCollection
, но он фактически заставил меня реализовать каждый метод дважды, то есть:
public class FlexCollection<T> : IFlexCollection where T : FlexItem, new()
{
public void Add(T item) { ... } // to use in generic calls
public void Add(object item) { ... } // to use for calls from within FlexItem
...
}
Тогда я узнал, что могу сделать FlexItem самим универсальным классом! Тогда специализация может содержать ссылку на сбор объектов этой специализации (что вполне логично). Поэтому:
public class FlexItem<T> where T : FlexItem<T>, new()
{
public FlexCollection<T> ReferenceToParentCollection;
...
}
public class FlexCollection<T> where T : FlexItem<T>, new()
{
public void Add(T item) { ... }
...
}
Теперь я могу объявить некоторую специализацию FlexItem<T>
и соответствующую коллекцию:
public class BasicItem : FlexItem<BasicItem> { public int A; }
public class BasicCollection : FlexCollection<BasicItem> { };
Проблема возникает, когда я пытаюсь расширить эти классы для хранения дополнительных полей. То есть Мне нужен класс ExtendedItem
, который содержит поле B
в дополнение к полю A
:
public class ExtendedItem : BasicItem { public int B; }
public class ExtendedCollection : FlexCollection<ExtendedItem> { };
И дело в том, что ExtendedItem
является подклассом FlexItem<BasicItem>
, а не FlexItem<ExtendedItem>
. Поэтому невозможно объявить ExtendedCollection
, как указано выше. Это вызывает ошибку компиляции:
The type 'Demo.ExtendedItem' must be convertible to
'Demo.FlexItem<Demo.ExtendedItem>' in order to use it as parameter 'T'
in the generic type or method 'Demo.BasicCollection<T>'
Есть ли способ избежать такого столкновения типа?