Puisque true
n'est pas un type de chaîne, comment est null + true
une chaîne?
string s = true; //Cannot implicitly convert type 'bool' to 'string'
bool b = null + true; //Cannot implicitly convert type 'string' to 'bool'
Quelle est la raison derrière cela?
Réponses:
Aussi bizarre que cela puisse paraître, il s'agit simplement de suivre les règles de la spécification du langage C #.
De la section 7.3.4:
Alors, parcourons ceci à tour de rôle.
X est le type nul ici - ou pas du tout un type, si vous voulez y penser de cette façon. Il ne fournit aucun candidat. Y est
bool
, qui ne fournit aucun+
opérateur défini par l'utilisateur . Ainsi, la première étape ne trouve aucun opérateur défini par l'utilisateur.Le compilateur passe ensuite au deuxième point, en regardant à travers l'opérateur binaire prédéfini + implémentations et leurs formes levées. Ceux-ci sont énumérés dans la section 7.8.4 de la spécification.
Si vous regardez à travers ces opérateurs prédéfinis, le seul qui soit applicable est
string operator +(string x, object y)
. Ainsi, l'ensemble candidat a une seule entrée. Cela rend le dernier point très simple ... la résolution de surcharge sélectionne cet opérateur, donnant un type d'expression global destring
.Un point intéressant est que cela se produira même s'il existe d'autres opérateurs définis par l'utilisateur disponibles sur des types non mentionnés. Par exemple:
C'est bien, mais il n'est pas utilisé pour un littéral nul, car le compilateur ne sait pas chercher
Foo
. Il ne sait à prendre en compte questring
parce qu'il s'agit d'un opérateur prédéfini explicitement répertorié dans la spécification. (En fait, ce n'est pas un opérateur défini par le type de chaîne ... 1 ) Cela signifie que la compilation échouera:D'autres types de deuxième opérande utiliseront bien sûr d'autres opérateurs:
1 Vous vous demandez peut-être pourquoi il n'y a pas d'opérateur string +. C'est une question raisonnable, et je ne fais que deviner la réponse, mais considérez cette expression:
S'il
string
n'y avait pas de casse spéciale dans le compilateur C #, cela finirait aussi efficacement:Cela a donc créé deux chaînes intermédiaires inutiles. Cependant, comme il existe un support spécial dans le compilateur, il est en fait capable de compiler ce qui précède comme:
qui peut créer une seule chaîne exactement de la bonne longueur, en copiant toutes les données une seule fois. Agréable.
la source
true
ne pas être convertible enstring
. Si l'expression était valide, le type seraitstring
, mais dans ce cas, l'échec de la conversion en chaîne fait de l'expression entière une erreur et n'a donc pas de type.x
est de typestring
. Notez que la signature utilisée ici eststring operator+(string, object)
- elle est convertiebool
enobject
(ce qui est bien), pas enstring
.La raison en est qu'une fois que vous avez introduit le,
+
les règles de liaison de l'opérateur C # entrent en jeu. Il considérera l'ensemble des+
opérateurs disponibles et sélectionnera la meilleure surcharge. L'un de ces opérateurs est le suivantCette surcharge est compatible avec les types d'argument de l'expression
null + true
. Par conséquent, il est sélectionné comme opérateur et est évalué comme essentiellement((string)null) + true
ce qui correspond à la valeur"True"
.La section 7.7.4 de la spécification du langage C # contient les détails autour de cette résolution.
la source
operator+
pourstring
. Au lieu de cela, il n'existe que dans l'esprit du compilateur et il le traduit simplement en appels àstring.Concat
Le compilateur part à la recherche d'un opérateur + () qui peut d'abord prendre un argument nul. Aucun des types de valeur standard n'est qualifié, null n'est pas une valeur valide pour eux. La seule et unique correspondance est System.String.operator + (), il n'y a pas d'ambiguïté.
Le 2ème argument de cet opérateur est également une chaîne. Cela va kapooey, ne peut pas convertir implicitement bool en chaîne.
la source
Fait intéressant, en utilisant Reflector pour inspecter ce qui est généré, le code suivant:
est transformé en ceci par le compilateur:
Le raisonnement derrière cette "optimisation" est un peu bizarre je dois dire, et ne rime pas avec la sélection d'opérateurs que j'attendrais.
En outre, le code suivant:
se transforme en
où
string b = true;
n'est en fait pas accepté par le compilateur.la source
null
sera converti en chaîne nulle, et il y a un convertisseur implicite de bool en chaîne donc letrue
sera converti en chaîne et ensuite, l'+
opérateur sera appliqué: c'est comme: string str = "" + true.ToString ();si vous le vérifiez avec Ildasm:
string str = null + true;
c'est comme ci-dessous:
la source
Fou?? Non, il doit y avoir une raison derrière cela.
Quelqu'un appelle
Eric Lippert
...la source
La raison en est la commodité (la concaténation de chaînes est une tâche courante).
Comme BoltClock l'a dit, l'opérateur '+' est défini sur les types numériques, les chaînes et peut également être défini pour nos propres types (surcharge d'opérateurs).
S'il n'y a pas d'opérateur '+' surchargé sur les types de l'argument et qu'il ne s'agit pas de types numériques, le compilateur utilise par défaut la concaténation de chaînes.
Le compilateur insère un appel à
String.Concat(...)
lorsque vous concaténez en utilisant '+', et l'implémentation de Concat appelle ToString sur chaque objet qui lui est passé.la source