2010-04-10 5 views
3

Je me demandais si quelqu'un pouvait me dire si ce genre de comportement est possible en C# 4.0C# .NET 4.0 et Generics

J'ai une hiérarchie d'objets que je voudrais garder fortement typé. Quelque chose comme ça

class ItemBase {} 

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


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

Ce que je veux être en mesure de faire pour avoir quelque chose comme ça

ItemType item = new EquipmentType(); 

Et je veux item.Base pour revenir ItemBase type. Fondamentalement, je veux savoir s'il est assez intelligent pour générique fortement typé à une classe de base sans le typage fort. Avantage de cet être, je peux simplement renvoyer un ItemType à un EquipmentType et obtenir à nouveau toute la typicité.

je penserai à tout faux ...

Répondre

4

Vous parlez de covariance qui vous permettra de le faire:

ItemType<object> item = new EquipmentType(); 

Vous ne pouvez le faire en C# 4 pour les raisons suivantes:

  1. covariance générique fonctionne uniquement sur Interfaces, tableaux et types de délégués, et non classes de base
  2. Votre classe ItemType utilise T comme paramètre de type in/out, ce qui signifie qu'il reçoit un T et renvoie également un T.

Le numéro 2 est le problème principal car s'il était autorisé, le code suivant devrait être compilable, mais échouer lors de l'exécution.

// 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

Non, car ItemType aussi loin que le compilateur est concerné est un type distinct de ItemType<EquipmentBase> ou ItemType<Foo>. Tous les trois sont traités comme des types uniques et ils ne peuvent pas se représenter les uns les autres.

Dans vos déclarations de classe, vous l'avez déclaré comme ItemType<T> et donc ItemType serait un type indéfini qui ne serait pas compilé.

Au mieux, vous pouvez utiliser un objet ItemType<EquipmentBase> pour représenter EquipmentType ou toute autre classe dérivée de ItemType<EquipmentBase> mais pas ItemType<PersonType>.

+1

Cela ne fonctionnera pas non plus dans C# 4 à cause des 2 raisons que j'ai notées dans ma réponse. Mais même si ItemType était à la place IItemType , le fait qu'il ait besoin de T comme paramètre in et out exclut effectivement l'utilisation souhaitée. – Josh

0

Je ne pense pas que les nouvelles fonctionnalités de C# 4.0 vous aider là-bas. Cependant, il existe un moyen de contourner cela qui fonctionne déjà depuis que les génériques ont été introduits: vous créez une classe de base abstraite avec le même nom que la classe générique et mettez tous les membres que vous voulez et qui n'ont pas besoin d'accepter ou de retourner un argument le type générique, comme suit:

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; } 
}