Comment est null + true une chaîne?

Puisque true n’est pas un type de chaîne, comment est-ce que null + true une chaîne?

 ssortingng s = true; //Cannot implicitly convert type 'bool' to 'ssortingng' bool b = null + true; //Cannot implicitly convert type 'ssortingng' to 'bool' 

Quelle est la raison derrière cela?

Aussi bizarre que cela puisse paraître, il suit simplement les règles du langage C #.

De la section 7.3.4:

Une opération de la forme x op y, où op est un opérateur binary surchargeable, x est une expression de type X, et y est une expression de type Y, est traitée comme suit:

  • L’ensemble des opérateurs candidats définis par l’utilisateur fournis par X et Y pour l’opérateur d’opération op (x, y) est déterminé. L’ensemble est constitué de l’union des opérateurs candidats fournis par X et des opérateurs candidats fournis par Y, chacun déterminé à l’aide des règles du § 7.3.5. Si X et Y sont du même type, ou si X et Y sont dérivés d’un type de base commun, les opérateurs candidats partagés ne se produisent qu’une seule fois dans l’ensemble combiné.
  • Si le jeu d’opérateurs candidats définis par l’utilisateur n’est pas vide, il devient alors l’ensemble des opérateurs candidats pour l’opération. Sinon, les implémentations d’opérateur binarys prédéfinies, y compris leurs formes levées, deviennent l’ensemble des opérateurs candidats pour l’opération. Les implémentations prédéfinies d’un opérateur donné sont spécifiées dans la description de l’opérateur (§7.8 à §7.12).
  • Les règles de résolution de surcharge du § 7.5.3 sont appliquées à l’ensemble des opérateurs candidats pour sélectionner le meilleur opérateur par rapport à la liste d’arguments (x, y), et cet opérateur devient le résultat du processus de résolution de surcharge. Si la résolution de la surcharge ne parvient pas à sélectionner un seul opérateur, une erreur de délai de liaison se produit.

Alors, passons à travers cela à tour de rôle.

X est le type null 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 parcourant les implémentations binarys prédéfinies de l’opérateur binary et leurs formes levées. Celles-ci sont listées dans la section 7.8.4 de la spécification.

Si vous parcourez ces opérateurs prédéfinis, le seul qui soit applicable est l’ ssortingng operator +(ssortingng x, object y) . Donc, le jeu de candidats a une seule entrée. Cela rend le dernier sharepoint la puce très simple … la résolution de la surcharge sélectionne cet opérateur, donnant un type d’expression global de la ssortingng .

Un point intéressant est que cela se produira même si d’autres opérateurs définis par l’utilisateur sont disponibles sur les types non mentionnés. Par exemple:

 // Foo defined Foo operator+(Foo foo, bool b) Foo f = null; Foo g = f + true; 

C’est bien, mais il n’est pas utilisé pour un littéral nul, car le compilateur ne sait pas dans Foo . Il sait seulement prendre en compte la ssortingng car c’est un opérateur prédéfini explicitement listé 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 cela ne pourra pas être compilé:

 // Error: Cannot implicitly convert type 'ssortingng' to 'Foo' Foo f = null + true; 

D’autres types de second opérande utiliseront d’autres opérateurs, bien sûr:

 var x = null + 0; // x is Nullable var y = null + 0L; // y is Nullable var z = null + DayOfWeek.Sunday; // z is Nullable 

1 Vous vous demandez peut-être pourquoi il n’y a pas d’opérateur ssortingng +. C’est une question raisonnable, et je ne fais que deviner la réponse, mais considérons cette expression:

 ssortingng x = a + b + c + d; 

Si ssortingng n’avait pas de cas particulier dans le compilateur C #, cela finirait aussi bien:

 ssortingng tmp0 = (a + b); ssortingng tmp1 = tmp0 + c; ssortingng x = tmp1 + d; 

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 comstackr ce qui précède comme suit:

 ssortingng x = ssortingng.Concat(a, b, c, d); 

qui peut créer une seule chaîne de la même longueur, en copiant toutes les données exactement une fois. Agréable.

La raison en est que, 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 suivant

 ssortingng operator +(ssortingng x, object y) 

Cette surcharge est compatible avec les types d’argument de l’expression null + true . Par conséquent, il est sélectionné en tant qu’opérateur et est évalué essentiellement ((ssortingng)null) + true ce qui donne la valeur "True" .

La section 7.7.4 de la spécification du langage C # contient les détails relatifs à cette résolution.

Le compilateur va chercher 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.Ssortingng.operator + (), il n’y a pas d’ambiguïté.

Le deuxième argument de cet opérateur est également une chaîne. Cela va kapooey, ne peut pas implicitement convertir bool en ssortingng.

Fait intéressant, en utilisant Reflector pour inspecter ce qui est généré, le code suivant:

 ssortingng b = null + true; Console.WriteLine(b); 

est transformé en ceci par le compilateur:

 Console.WriteLine(true); 

Le raisonnement derrière cette “optimisation” est un peu étrange, je dois le dire, et ne rime pas avec le choix de l’opérateur auquel je m’attendrais.

En outre, le code suivant:

 var b = null + true; var sb = new SsortingngBuilder(b); 

est transformé en

 ssortingng b = true; SsortingngBuilder sb = new SsortingngBuilder(b); 

ssortingng b = true; n’est en fait pas accepté par le compilateur.

null sera converti en chaîne nulle, et il y aura un convertisseur implicite de bool en ssortingng pour que le true soit converti en ssortingng et que l’opérateur + sera appliqué: c’est comme: ssortingng str = “” + true.ToSsortingng ();

si vous vérifiez avec Ildasm:

ssortingng str = null + true;

c’est comme ci-dessous:

 .locals init ([0] ssortingng str) IL_0000: nop IL_0001: ldc.i4.1 IL_0002: box [mscorlib]System.Boolean IL_0007: call ssortingng [mscorlib]System.Ssortingng::Concat(object) IL_000c: stloc.0 
 var b = (null + DateTime.Now); // Ssortingng var b = (null + 1); // System.Nullable | same with System.Single, System.Double, System.Decimal, System.TimeSpan etc var b = (null + new Object()); // Ssortingng | same with any ref type 

Fou?? Non, il doit y avoir une raison derrière cela.

Quelqu’un appelle Eric Lippert

La raison en est la commodité (concaténer des chaînes est une tâche courante).

Comme BoltClock l’a dit, l’opérateur ‘+’ est défini sur des types numériques, des chaînes, et peut être défini pour nos propres types (surcharge d’opérateur).

S’il n’y a pas d’opérateur ‘+’ surchargé sur les types d’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 à Ssortingng.Concat(...) lorsque vous concaténez à l’aide de ‘+’, et l’implémentation des appels Concat ToSsortingng sur chaque object est transmise.