Dado true
que no es un tipo de cadena, ¿cómo es null + true
una cadena?
string s = true; //Cannot implicitly convert type 'bool' to 'string'
bool b = null + true; //Cannot implicitly convert type 'string' to 'bool'
Cuál es la razón detrás de esto?
Respuestas:
Por extraño que parezca, se trata simplemente de seguir las reglas de la especificación del lenguaje C #.
De la sección 7.3.4:
Entonces, repasemos esto a su vez.
X es el tipo nulo aquí, o no es un tipo en absoluto, si quieres pensarlo de esa manera. No proporciona ningún candidato. Y es
bool
, que no proporciona ningún+
operador definido por el usuario . Entonces, el primer paso no encuentra operadores definidos por el usuario.El compilador luego pasa al segundo punto, mirando a través de las implementaciones de operadores binarios predefinidos y sus formas levantadas. Estos se enumeran en la sección 7.8.4 de la especificación.
Si observa esos operadores predefinidos, el único que es aplicable es
string operator +(string x, object y)
. Entonces, el conjunto de candidatos tiene una sola entrada. Eso hace que el punto final sea muy simple ... la resolución de sobrecarga elige ese operador, dando un tipo de expresión general destring
.Un punto interesante es que esto ocurrirá incluso si hay otros operadores definidos por el usuario disponibles en tipos no mencionados. Por ejemplo:
Eso está bien, pero no se usa para un literal nulo, porque el compilador no sabe buscar
Foo
. Solo sabe considerarstring
porque es un operador predefinido que se enumera explícitamente en la especificación. (De hecho, es no un operador definido por el tipo de cadena ... 1 ) Esto significa que este dejará de compilar:Otros tipos de segundo operando usarán algunos otros operadores, por supuesto:
1 Puede que se pregunte por qué no hay un operador + cadena. Es una pregunta razonable, y solo estoy adivinando la respuesta, pero considere esta expresión:
Si
string
no tuviera una carcasa especial en el compilador de C #, esto terminaría con la misma eficacia:Entonces eso creó dos cadenas intermedias innecesarias. Sin embargo, debido a que hay un soporte especial dentro del compilador, en realidad es capaz de compilar lo anterior como:
que puede crear una sola cadena de exactamente la longitud correcta, copiando todos los datos exactamente una vez. Agradable.
fuente
true
no ser convertible astring
. Si la expresión fuera válida, el tipo lo seríastring
, pero en este caso, la falta de conversión a cadena hace que toda la expresión sea un error y, por lo tanto, no tiene tipo.x
es de tipostring
. Tenga en cuenta que la firma utilizada aquí esstring operator+(string, object)
: se está convirtiendobool
aobject
(lo cual está bien), no astring
.La razón es porque una vez que introduce el
+
operador C #, las reglas de enlace entran en juego. Considerará el conjunto de+
operadores disponibles y seleccionará la mejor sobrecarga. Uno de esos operadores es el siguienteEsta sobrecarga es compatible con los tipos de argumentos de la expresión
null + true
. Por lo tanto, se selecciona como operador y se evalúa como esencialmente lo((string)null) + true
que evalúa el valor"True"
.La sección 7.7.4 de la especificación del lenguaje C # contiene los detalles sobre esta resolución.
fuente
operator+
parastring
. En cambio, solo existe en la mente del compilador y simplemente lo traduce en llamadas parastring.Concat
El compilador busca un operador + () que pueda tomar un argumento nulo primero. Ninguno de los tipos de valor estándar califica, nulo no es un valor válido para ellos. La única coincidencia es System.String.operator + (), no hay ambigüedad.
El segundo argumento de ese operador también es una cadena. Eso va kapooey, no puede convertir implícitamente bool en cadena.
fuente
Curiosamente, usando Reflector para inspeccionar lo que se genera, el siguiente código:
es transformado en esto por el compilador:
El razonamiento detrás de esta "optimización" es un poco extraño, debo decirlo, y no rima con la selección del operador que esperaría.
Además, el siguiente código:
se transforma en
donde en
string b = true;
realidad no es aceptado por el compilador.fuente
null
se convertirá en una cadena nula, y hay un convertidor implícito de bool a cadena, por lotrue
que se convertirá en cadena y luego+
se aplicará el operador: es como: cadena str = "" + true.ToString ();si lo verifica con Ildasm:
string str = null + true;
es como abajo:
fuente
¿¿Loco?? No, debe haber una razón detrás de esto.
Alguien llame
Eric Lippert
...fuente
La razón de esto es la conveniencia (la concatenación de cadenas es una tarea común).
Como dijo BoltClock, el operador '+' se define en tipos numéricos, cadenas y también se puede definir para nuestros propios tipos (sobrecarga del operador).
Si no hay un operador '+' sobrecargado en los tipos del argumento y no son tipos numéricos, el compilador usa por defecto la concatenación de cadenas.
El compilador inserta una llamada a
String.Concat(...)
cuando concatenas usando '+', y la implementación de Concat llama a ToString en cada objeto que se le pasa.fuente