112 votes

Comment est null + vrai une chaîne de caractères?

Depuis true n'est pas un type de chaîne, comment est - null + true une chaîne de caractères ?

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?

148voto

Jon Skeet Points 692016

Bizarre que cela puisse paraître, c'est tout simplement en suivant les règles du langage C# spec.

À partir de la section 7.3.4:

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

  • L'ensemble des candidats définis par l'utilisateur opérateurs fournis par X et Y pour le fonctionnement de l'opérateur op(x, y) est déterminé. L'ensemble se compose de l'union du candidat opérateurs fournis par X et le candidat opérateurs fournis par Y, chaque déterminé en utilisant les règles du §7.3.5. Si X et Y sont du même type, ou si X et Y sont dérivées à partir d'une base commune, partagée candidat opérateurs se trouvent seulement dans l'ensemble une fois.
  • Si l'ensemble des candidats défini par l'utilisateur des opérateurs n'est pas vide, alors cela devient de l'ensemble des candidats opérateurs pour l'exploitation. Sinon, le prédéfinies de l'opérateur binaire op mises en œuvre, y compris leur levée de formes, de devenir l'ensemble des candidats opérateurs pour l'exploitation. Les prédéfinis des implémentations d'un opérateur donné sont spécifiés dans la description de l'opérateur (§7.8 à travers §7.12).
  • La résolution de surcharge règles du §7.5.3 sont appliquées à l'ensemble des candidats opérateurs de sélectionner le meilleur de l'opérateur à l'égard de la liste d'arguments (x, y), et cet opérateur devient le résultat de la surcharge du processus de résolution. Si la résolution de surcharge ne parvient pas à sélectionner un seul opérateur, une liaison se produit une erreur.

Donc, nous allons marcher à travers ce tour.

X est le type null ici - ou pas du tout, si vous voulez penser de cette façon. Ce n'est pas de fournir tout les candidats. Y est - bool, ce qui n'est pas définie par l'utilisateur + opérateurs. Donc, la première étape ne trouve pas définie par l'utilisateur opérateurs.

Le compilateur se déplace ensuite sur le deuxième point, en regardant à travers les prédéfinis opérateur binaire + implémentations et de leur levée de formes. Ces sont listées dans l'article 7.8.4 de la spécification.

Si vous regardez à travers ceux des opérateurs prédéfinis, le seul l'un qui est applicable est - string operator +(string x, object y). Si le candidat a une seule entrée. Qui fait le point final très simple... de résolution de surcharge sélectionne l'opérateur, en lui donnant une expression globale type d' string.

Un point intéressant est que ce sera le cas même si il y a d'autres définis par l'utilisateur des opérateurs disponibles sur pas mentionner les types. Par exemple:

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

C'est très bien, mais il n'est pas utilisé pour un littéral null, parce que le compilateur ne sait pas regarder en Foo. Il ne connaît que de considérer string parce que c'est un prédéfini opérateur explicitement mentionnées dans la spécification. (En fait, c'est pas un opérateur défini par le type de chaîne... 1), cela signifie que l'on va à l'échec de compilation:

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

Autres deuxième opérande types d'utiliser certains autres opérateurs, bien sûr:

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

1 - Vous demandez peut-être pourquoi il n'y a pas une chaîne opérateur+. C'est une question raisonnable, et je suis le seul à en deviner la réponse, mais considérer cette expression:

string x = a + b + c + d;

Si string avait rien de spécial à-boîtier dans le compilateur C#, cela constituerait effectivement:

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

Voilà donc créé deux inutiles intermédiaire des chaînes de caractères. Cependant, parce qu'il y a un soutien spécial dans le compilateur, c'est effectivement en mesure de compiler les ci-dessus:

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

qui peut créer juste une seule chaîne de exactement la bonne longueur, la copie de toutes les données exactement une fois. Nice.

44voto

JaredPar Points 333733

La raison en est qu'une fois que vous introduisez l' + le C# opérateur de liaison règles entrent en jeu. Il considère l'ensemble de l' + opérateurs disponibles et de sélectionner le meilleur de surcharge. L'un de ces opérateurs est le suivant

string operator +(string x, object y)

Cette surcharge est compatible avec les types d'argument dans l'expression null + true. Par conséquent, il est choisi comme opérateur et est évalué comme étant essentiellement ((string)null) + true qui évalue à la valeur "True".

Section 7.7.4 du langage C# spec contient les détails autour de cette résolution .

11voto

Hans Passant Points 475940

Le compilateur va à la chasse pour un opérateur+() peut prendre un argument null premier. Aucun de la valeur standard des types de qualifier, null n'est pas une valeur valide pour eux. Le seul et unique match du Système.Chaîne de caractères.operator+(), il n'y a pas d'ambiguïté.

Le 2ème argument de l'opérateur est également une chaîne de caractères. Qui va kapooey, impossible de convertir implicitement le type bool string.

10voto

Peter Lillevold Points 20689

Il est intéressant de noter, à l'aide de Réflecteurs pour inspecter ce qui est généré, le code suivant:

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

est transformé en cette par le compilateur:

Console.WriteLine(true);

Le raisonnement derrière cette "optimisation" est un peu bizarre je dois dire, et ne rime pas avec la sélection de l'opérateur je m'attends.

Aussi, le code suivant:

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

est transformé en

string b = true; 
StringBuilder sb = new StringBuilder(b);

string b = true; n'est pas réellement accepté par le compilateur.

8voto

Saeed Amiri Points 16317

null sera convertie en une chaîne vide, et il est implicite convertisseur de bool string donc l' true sera jeté à la chaîne et puis, + opérateur sera appliquée: c'est comme: string str = "" + vrai.ToString();

si vous vérifiez avec Ildasm:

string str = null + true;

c'est comme ci-dessous:

.locals init ([0] string str)
  IL_0000:  nop
  IL_0001:  ldc.i4.1
  IL_0002:  box        [mscorlib]System.Boolean
  IL_0007:  call       string [mscorlib]System.String::Concat(object)
  IL_000c:  stloc.0

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X