Question

public class Foo : IFooBarable {...}
public class Bar : IFooBarable {...}

Alors pourquoi cela ne va compiler ...

int a = 1;
IFooBarable ting = a == 1 ? new Foo() : new Bar();

mais cela ...

IFooBarable ting = a == 1 ? new Foo() : new Foo();
IFooBarable ting = a == 1 ? new Bar() : new Bar();
Était-ce utile?

La solution

Le compilateur essaie d'abord d'évaluer l'expression droite:

? new Foo() : new Bar();

Il n'y a pas de conversion implicite entre ces deux où le message d'erreur. Vous pouvez faire ceci:

IFooBarable ting = a == 1 ? (IFooBarable)(new Foo()) : (IFooBarable)(new Bar());

Autres conseils

Ceci est couvert dans la section 7.13 de la spécification du langage C #. Essentiellement ce qui tue ce scénario est qu'il doit y avoir une conversion implicite entre les types de 2 valeurs pour les opérandes ternaires. Cette conversion est considérée dans le abscence du type de la variable.

Alors, soit Foo doit être convertible en Bar ou vice versa. Ni est donc une erreur de compilation se produit.

Le dernier 2 travail bien parce qu'ils considèrent que le type 1 (soit Foo ou Bar). Parce qu'ils sont du même type déterminer le type de l'expression est simple et cela fonctionne très bien.

Il suffit d'ajouter un peu aux réponses affichées ici: il y a deux lignes directrices de conception qui conduisent à cette spécification

.

La première est que nous raison « de l'intérieur vers l'extérieur ». Quand vous dites

double x = 2 + y;

nous avons d'abord travailler sur le type de x, le type de 2, le type de y, puis le type de (2 + y), et enfin, nous élaborons si x et (2 + y) ont compatible les types. Mais nous ne l'utilisons pas le type de x pour décider ce que le type de 2, y ou 2 + y est.

La raison pour cela est une bonne règle est parce que souvent le type de « récepteur » est exactement ce que nous essayons de travailler:

void M(Foo f) {}
void M(Bar b) {}
...
M(x ? y : z);

Que devons-nous faire ici? Nous devons travailler sur le type de l'expression conditionnelle afin de faire la résolution de surcharge, afin de déterminer si cela va Foo ou Bar. Par conséquent, nous ne pouvons pas utiliser le fait que ce soit, par exemple, va Foo dans notre analyse du type de l'expression conditionnelle! C'est un problème de la poule et de l'œuf.

L'exception à cette règle est des expressions lambda, qui ne prennent leur type de leur contexte. Faire que le travail de fonction était incroyablement compliquée correctement; voir mon série blog sur les expressions lambda vs méthodes anonymes si vous êtes intéressé.

Le deuxième élément est que nous ne « magie » un type pour vous. Administré un tas de choses dont il faut déduire un type, on en déduit toujours un type qui était en fait juste en face de nous.

Dans votre exemple, l'analyse va comme ceci:

  • travailler le type de la conséquence
  • travailler le type de l'alternative
  • trouver le meilleur type qui est compatible avec la conséquence et l'alternative
  • assurez-vous qu'il ya une conversion du type de l'expression conditionnelle du type de la chose qui utilise l'expression conditionnelle.

Conformément au premier point, nous ne raisonnons pas à l'extérieur à l'intérieur ; nous n'utilisons pas le fait que nous savons que le type de la variable que nous allons pour travailler le type de l'expression. Mais la chose intéressante est maintenant que quand vous avez

b ? new Cat() : new Dog()

nous disons « le type de l'expression conditionnelle est le meilleur type dans l'ensemble {Cat, Dog} ». Nous ne disons pas « le type de l'expression conditionnelle est le meilleur type compatible avec les chiens et chats ». Ce serait des mammifères, mais nous ne faisons pas cela. Au lieu de cela, nous disons « le résultat doit être quelque chose, nous avons vu », et de ces deux choix, ni est le grand vainqueur. Si vous avez dit

b ? (Animal) (new Cat()) : new Dog()

nous avons un choix entre l'animal et le chien, et des animaux est le grand vainqueur.

Maintenant, notez que nous ne mettons pas en œuvre correctement fait la spécification C # lors de cette analyse de type! Pour plus de détails sur l'erreur, voir mon

Parce que le type de l'expression conditionnelle est toujours déduit de ses deux parties, et non pas de la variable à laquelle doit être appliqué le résultat. Cette conclusion ne fonctionne que lorsque les types sont égaux ou une référence est compatible avec l'autre. Dans ce cas, aucun des deux types est compatible référence à l'autre.

scroll top