(Suite aux commentaires de la réponse acceptée).
Oui, c'est une partie très, très confuse de la spécification. Toute la partie concernant les "types englobants", en particulier, est profondément défectueuse. Cela fait plusieurs années que j'essaie de trouver le temps de réécrire complètement cette section pour en faire quelque chose de plus cohérent, mais cela n'a jamais été une priorité suffisante.
Essentiellement ce que nous avons ici est une contradiction ; nous dites qu'il n'y a pas de conversions implicites définies par l'utilisateur impliquant des interfaces, mais il est clair que ce n'est pas vrai dans ce cas ; il y a une conversion implicite définie par l'utilisateur de IC vers Foo<IC>
, démontrée par le fait qu'une chaîne va à Foo<IC>
via cette conversion.
Ce que nous devrions vraiment mieux souligner, c'est cette ligne que vous avez citée :
En particulier, il n'est pas possible de redéfinir une conversion implicite ou ou explicite déjà existante.
C'est ce qui motive tout cela : le désir de ne jamais laisser penser que l'on effectue un test de type préservant la représentation alors qu'en fait, on appelle une méthode définie par l'utilisateur. Considérez par exemple cette variation :
interface IBar {}
interface IFoo : IBar {}
class Foo<T> : IFoo
{
public static explicit operator Foo<T>(T input) { whatever }
}
class Blah : Foo<IBar> {}
...
IBar bar = new Blah();
Foo<IBar> foo = (Foo<IBar>)bar;
Maintenant, Est-ce que cela appelle la conversion explicite définie par l'utilisateur ou non ? L'objet est réellement dérivé de Foo, on peut donc espérer qu'il ne le soit pas ; il devrait s'agir d'un simple test de type et d'une affectation de référence, et non d'un appel à une méthode d'aide. Un cast sur une valeur d'interface est toujours traité comme un test de type car il est presque toujours possible que l'objet soit réellement de ce type et implémente réellement cette interface. Nous ne voulons pas vous priver de la possibilité d'effectuer une conversion bon marché préservant la représentation.