2009-01-07 10 views
13

Vous ne savez pas exactement comment formuler la question, car c'est un "pourquoi ça ne marche pas?" type de requête.Contraintes génériques et implémentation d'interface/héritage

J'ai réduit mon problème particulier jusqu'à ce code:

public interface IFoo 
{ 
} 

public class Foo : IFoo 
{ 
} 

public class Bar<T> where T : IFoo 
{ 
    public Bar(T t) 
    { 
    } 

    public Bar() 
     : this(new Foo()) // cannot convert from 'Foo' to 'T' 
    { 
    } 
} 

Maintenant, le type générique T dans la classe Bar<T>doit mettre en œuvre IFoo. Alors pourquoi le compilateur me donne-t-il l'erreur dans le commentaire? Sûrement une instance de Foo est un IFoo, et peut donc être passé en tant que représentant du type générique T?

Est-ce une limitation du compilateur ou manque-t-il quelque chose?

Répondre

13

Vous pourriez aussi avoir une Fiz qui implémente IFoo qui ne se rapporte à Foo de toute autre manière:

public interface IFoo 
{ 
} 

public class Foo : IFoo 
{ 
} 

public class Fiz : IFoo 
{ 
} 

Foo foo = new Foo(); 
Fiz fiz = foo; // Not gonna compile. 

Ce que vous voulez est probablement plus comme:

public class Bar<T> where T : IFoo, new() 
{ 
    public Bar(T t) 
    { 
    } 

    public Bar() 
     : this(new T()) 
    { 
    } 
} 

vous pouvez avoir

Bar<Foo> barFoo = new Bar<Foo>(); 
Bar<Fiz> barFiz = new Bar<Fiz>(); 
+0

C'est gentil car je ne savais pas que vous pourriez la nouvelle chose T(), vous venez de sauver ma vie dans un projet sur lequel je travaille. À votre santé :) –

2

Si vous créez une classe Baz puis le type générique Bar baz = new Bar(), new Foo() tel que défini par votre surcharge constructeur, ne serait pas de type T, dans ce cas Baz.

+0

+1 Merci pour votre commentaire. Je donne à Andrew la réponse acceptée car il est un peu plus complet avec les exemples de code (et vous étiez à seulement 8 secondes d'intervalle). :) –

+0

D'accord (et merci). –

0

C'est parce que si vous créez une classe:

public class Fred : IFoo 
{ 
} 

Et puis instancier Bar<T> comme ceci:

var bar = new Bar<Fred>(); 

Ensuite, il constitue une violation des contraintes de la classe en tant que Foo n'est pas un Fred qui est le T actuel.

Vous pouvez le forcer à compiler en mettant la séquence de coulée (T)(IFoo)new Foo() dans le constructeur, mais vous obtiendrez un InvalidCastException lors de l'exécution si le type réel de T est incessible de Foo.

Questions connexes