Si j'ai une interface générique avec un paramètre de type covariant, comme ceci :
interface IGeneric<out T>
{
string GetName();
}
Et si je définis cette hiérarchie de classe :
class Base {}
class Derived1 : Base{}
class Derived2 : Base{}
Je peux alors implémenter l'interface deux fois sur une seule classe, comme ceci, en utilisant l'implémentation explicite de l'interface :
class DoubleDown: IGeneric<Derived1>, IGeneric<Derived2>
{
string IGeneric<Derived1>.GetName()
{
return "Derived1";
}
string IGeneric<Derived2>.GetName()
{
return "Derived2";
}
}
Si j'utilise le (non-générique) DoubleDown
et la transformer en IGeneric<Derived1>
o IGeneric<Derived2>
il fonctionne comme prévu :
var x = new DoubleDown();
IGeneric<Derived1> id1 = x; //cast to IGeneric<Derived1>
Console.WriteLine(id1.GetName()); //Derived1
IGeneric<Derived2> id2 = x; //cast to IGeneric<Derived2>
Console.WriteLine(id2.GetName()); //Derived2
Cependant, le fait de lancer le x
à IGeneric<Base>
donne le résultat suivant :
IGeneric<Base> b = x;
Console.WriteLine(b.GetName()); //Derived1
Je m'attendais à ce que le compilateur émette une erreur, car l'appel est ambigu entre les deux implémentations, mais il a renvoyé la première interface déclarée.
Pourquoi cela est-il autorisé ?
(inspiré par Une classe implémentant deux IObservables différentes ? . J'ai essayé de montrer à un collègue que cela allait échouer, mais d'une manière ou d'une autre, cela n'a pas fonctionné).
0 votes
Concernant
Console.WriteLine(b.GetName());
le site compilateur ne peut pas émettre d'erreur ; il a un IGeneric<Base> pour appeler getName et cet appel est parfaitement valide.0 votes
@MiserableVariable Le compilateur a plus qu'une implémentation valide - il en a deux. Dans d'autres scénarios, vous pouvez obtenir une erreur de compilation pour un appel ambigu, mais pas dans celui-ci, vous obtenez un comportement qui n'est pas spécifié.
0 votes
@SWeko, le compilateur ne regarde que l'élément statique type de
b
qui estIGeneric<Base>
sur lequel leGetName
l'appel est valide. Si vous suggérez que l'erreur devrait se trouver dansDoubleDown
ce n'est pas une erreur car il existe une règle bien définie selon laquelle la correspondance est non spécifiée.0 votes
@MiserableVariable comme je l'ai dit dans les autres réponses, ce cas n'est couvert par aucun des deux points du #13.4.4.
2 votes
Cette question ressemble beaucoup à une question que j'ai posée plus tôt (dont le lien figure dans la réponse de jam40jeff ci-dessous). Notez également qu'Eric Lippert a posé exactement cette question dans son billet de blog antérieur à C#-4.0. Covariance et contravariance en C# : Gérer l'ambiguïté . Il a supposé
IEnumerable<>
était covariant, et a fait une classeC
qui était à la foisIEnumerable<Giraffe>
yIEnumerable<Turtle>
. Ensuite, une instance de cette classe, par covariance, a étéIEnumerable<Animal>
. Donc, même ambiguïté.