2010-04-10 3 views
3

мне было интересно, если кто-нибудь может сказать мне, если такое поведение возможно в C# 4.0C# .NET 4.0 и Дженерики

У меня есть иерархия объектов я хотел бы, чтобы сильно типизированных. Что-то вроде этого

class ItemBase {} 

class ItemType<T> where T : ItemBase 
{ 
    T Base { get; set; } 
} 


class EquipmentBase : ItemBase {} 
class EquipmentType : ItemType<EquipmentBase> {} 

То, что я хочу быть в состоянии сделать, чтобы иметь что-то вроде этого

ItemType item = new EquipmentType(); 

И я хочу item.Base вернуться типа ItemBase. В принципе, я хочу знать, достаточно ли он достаточно умен для типичного типичного базового класса без сильной типизации. Преимущество этого я могу просто вернуть ItemType обратно в EquipmentType и снова получить всю жесткость.

я могу думать об этом все неправильно ...

ответ

4

Вы говорите о ковариации, который позволит вам сделать:

ItemType<object> item = new EquipmentType(); 

Вы не могли бы сделать это в C# 4 из-за следующих причин:

  1. Generic ковариационная работает только на интерфейсы, массивы и типы делегатов, а не базовые классы
  2. Класс ItemType использует T как параметр ввода/вывода, означающий, что он получает T, а также возвращает T.

Номер 2 является основной проблемой, поскольку, если бы это было разрешено, тогда следующий код должен был быть компилируемым, но не работать во время выполнения.

// this will not work 
ItemType<object> item = new EquipmentType(); 
item.Base = new Object(); // this seems ok but clearly isn't allowed 

Covariance and Contravariance FAQ

0

Нет, потому что ItemType насколько компилятор обеспокоен представляет собой отдельный вид из ItemType<EquipmentBase> или ItemType<Foo>. Все трое рассматриваются как уникальные типы, и они не могут представлять друг друга.

В объявлениях классов вы объявили его ItemType<T>, и поэтому ItemType будет неопределенным типом, который не будет компилироваться.

В лучшем случае, вы могли бы использовать ItemType<EquipmentBase> объект для представления EquipmentType или любого другого класса, производного от ItemType<EquipmentBase> но не ItemType<PersonType>.

+1

Это не сработает ни на C# 4 из-за двух причин, которые я заметил в своем ответе. Но даже если ItemType был вместо IItemType , тот факт, что ему нужен T как параметр in и out, эффективно исключает нужное использование. – Josh

0

Я не думаю, что новые возможности C# 4.0 поможет вам там. Тем не менее, существует путь вокруг этого, который уже работает с тех пор, как были введены обобщения: вы создаете абстрактный базовый класс с тем же именем, что и общий класс, и ставите все члены, которые вы хотите, и которые не должны принимать или возвращать аргумент общий тип, например:

class ItemBase { 
} 

abstract class ItemType { 
    public ItemBase Base { 
     get { return GetItemBase(); } 
     set { SetItemBase(value); } 
    } 

    protected abstract void SetItemBase(ItemBase value); 

    protected abstract ItemBase GetItemBase(); 
} 

class ItemType<T> : ItemType where T : ItemBase { 
    protected override sealed void SetItemBase(ItemBase value) { 
     Base = (T) value; 
    } 

    protected override sealed ItemBase GetItemBase() { 
     return Base; 
    } 

    public new T Base { get; set; } 
} 
Смежные вопросы