2010-07-03 8 views
5

Je pense que je dois manquer quelque chose, pourquoi je ne peux pas compiler ceci:Pourquoi ne pouvez-vous pas convertir un type générique ouvert contraint vers le type contraint?

class Foo<T> where T : Bar 
{ 
    T Bar; 
} 

abstract class Bar 
{ } 

class MyBar : Bar 
{ } 

static void Main(string[] args) 
{ 
    var fooMyBar = new Foo<MyBar>(); 
    AddMoreFoos(fooMyBar); 
} 

static void AddMoreFoos<T>(Foo<T> FooToAdd) where T : Bar 
{ 
    var listOfFoos = new List<Foo<Bar>>(); 
    listOfFoos.Add(FooToAdd); //Doesn't compile 
    listOfFoos.Add((Foo<Bar>)FooToAdd); //doesn't compile 
} 

Répondre

9

Vous êtes rendre les choses un peu plus confus qu'ils doivent être à l'aide d'une liste ici ... il est plus facile de voir l'effet de cette façon:

// This won't compile 
Foo<Bar> fooBar = new Foo<MyBar>(); 

Étant donné que cela ne compile pas , il est donc pas surprenant que vous ne pouvez pas ajouter un Foo<MyBar> à un List<Foo<Bar>>

alors pourquoi n'est pas un Foo<MyBar> un Foo<Bar>? Parce que les classes génériques ne sont pas covariantes.

La variance générique n'a été introduite que dans C# 4 - et ne fonctionne que pour les interfaces et les délégués. Ainsi, vous pouvez (en C# 4) faire:

IEnumerable<MyBar> x = new List<MyBar>(); 
IEnumerable<Bar> y = x; 

mais vous ne pouviez pas faire:

IList<MyBar> x = new List<MyBar>(); 
IList<Bar> y = x; 

J'ai une conversation tout à propos de la variance que vous pouvez télécharger à partir du NDC 2010 video site - il suffit de rechercher " variance".

3

Il ne compile pas parce que si vous deviez appeler votre méthode avec un Foo<int> l'appel échouera: vous essayez assumer un type spécifique pour votre paramètre générique.

Ce que vous devez utiliser à la place var listOfFoos = new List<Foo<T>>(), alors le Add devrait fonctionner.

(EDIT: également, la distribution fonctionnerait si vous avez utilisé Foo<T> - mais vous ne pouvez toujours pas supposer dans votre code que T est Bar).

+0

'si vous appelez votre méthode avec un Foo alors l'appel échouera' => mais cet appel ne compilera pas à cause de la contrainte générique, où T: Bar, non? Cependant, +1 pour la nouvelle liste >() car cela résout en fait mon vrai problème! –

+0

Bon point sur la contrainte. Confus de savoir pourquoi vous avez accepté l'autre réponse si j'ai résolu votre problème tho ... (Jon Skeet ou pas! ;-)) –

Questions connexes