2010-11-17 10 views
11

Como programador, esperaba que esto arrojara una excepción. ¿Hay alguna razón por la que trata null como ""?C# agregar string + null no arroja un error?

string s = "hello"; 
string t = null; 

Console.WriteLine(s + t); 

Salida:

hola

Sólo para enfatizar mi pregunta, ¿sabe por qué la decisión de convertir nulo en String.Empty se hizo? Esperaba que se agregara alguna cadena, pero había un problema más atrás donde no lo estaba recuperando correctamente y volvió con nulo. ¡El problema pasó desapercibido!

Aquí está un pseudocódigo de por qué creo que es malo (y por lo que se sorprendió al descubrir ningún error):

Se puede suponer sobrecargué ToString para dar el nombre de la persona o detalles acerca de ellos.

Person p = PersonDatabase.GetForName("Jimmy Gibbs"); 

Console.WriteLine("Name is: " + p.ToString()); 

se emite una excepción porque p es nula

String p = PersonDatabase.GetForName("Jimmy Gibbs").Name; 

Console.WriteLine("Name is: " + p); 

no lanza una excepción, a pesar de que p es nulo (se trata como "").

(Si quieres ser exigente y decir que no voy a ser capaz de obtener Nombre como GetforName será nula, lo veo como esta :)

String p = PersonDatabase.GetNameFromID(1234); // Returns a string or null if not found 

Console.WriteLine("Name is: " + p); 

(Si se utiliza este valor en una lista o matriz terminará con una entrada en blanco que es lo que rompió para mí, fue crear javascript e intentar obtener elemento por ID de "")

+2

WoW, y + null en mayúscula la primera letra que es un Plus :) – Bolu

+0

Solo puedo especular sobre por qué, pero un argumento a favor sería reducir la posibilidad de confundir a los desarrolladores novatos, que están acostumbrados a pensar en nulos excepciones como resultado de la desreferenciación; tenerlos causados ​​por los operadores podría ser poco intuitivo. No es un argumento muy bueno, en mi opinión, pero estaría en línea con el principio de menor sorpresa (si no agregas nada a algo, aún esperas tener algo). –

+0

Si puede usar string t = null, también debería poder usar otros operadores con null. – Bolu

Respuesta

6

El operador + se emite como string.Concat en la IL resultante.

s + t = string.Concat(s, t) 

y cuando se mira en la aplicación comprueba si los argumentos son nulos y devuelve String.Empty:

desensamblado con reflector:

[SecuritySafeCritical] 
public static string Concat(string str0, string str1) 
{ 
    if (IsNullOrEmpty(str0)) 
    { 
     if (IsNullOrEmpty(str1)) 
     { 
      return Empty; 
     } 
     return str1; 
    } 
    if (IsNullOrEmpty(str1)) 
    { 
     return str0; 
    } 
    int length = str0.Length; 
    string dest = FastAllocateString(length + str1.Length); 
    FillStringChecked(dest, 0, str0); 
    FillStringChecked(dest, length, str1); 
    return dest; 
} 
+1

¿Sabes por qué? Tuvimos un error desagradable como resultado de esto que pasó desapercibido. – NibblyPig

+0

Esto está documentado: http://msdn.microsoft.com/en-us/library/a6d350wd.aspx (se utiliza una cadena vacía en lugar de cualquier argumento nulo.) –

18

Desde el C# Language Specification:

7.8.4 Operador suma

Concatenación de cadenas:

operador de cadenas + (cadena x, cadena y); operador de cadena + (cadena x, objeto y); operador de cadena + (objeto x, cadena y);

Estas sobrecargas del operador binario + realizan la concatenación de cadenas. Si un operando de concatenación de cadenas es nulo, una cadena vacía es sustituida. De lo contrario, cualquier argumento que no sea de cadena se convierte a su cadena representación invocando el método virtual ToString heredado del objeto tipo . Si ToString devuelve nulo, se sustituye una cadena vacía .

+2

¿Por qué es una buena idea? – NibblyPig

+2

@SLC Me pregunto si tiene que ver con el hecho de que las cadenas son tipos de referencia pero se comportan como tipos de valores de muchas maneras (porque son inmutables). Entonces, hacer que se comporte de esta manera (cuando se usa el operador +) encaja con este concepto. –

0

Los operadores definidos por el usuario son solo métodos estáticos y, por supuesto, pueden aceptar los parámetros null. Esto es, por ejemplo, realmente útil para los delegados.

Así que la aceptación de cadenas null no es una decisión técnica, sino de diseño. Y a veces es útil tratar null como "", ya que una gran cantidad de código de usuario los trata de la misma manera.

0

Si tengo una naranja y agrego otra naranja, ahora tengo dos naranjas.

Si tengo una naranja y no agrego NADA, todavía tengo una naranja.

Para mí agregar NULL a una cadena y obtener la cadena original parece perfectamente intuitiva y semántica. NullReferenceExceptions debe reservarse para acceder a Propiedades o métodos de instancia en instancias que no existen, ej.

string myString = null; 
string lowerCaseString = myString.ToLower(); 

tiraría comprensiblemente un NullReferenceException porque estoy tratando de acceder a la ToLower método de instancia() en una referencia que no existe, por lo tanto nulo Referencia excepción (es decir. Que hay una cosa en la pila, pero nada en el Heap).

Tener operaciones concat de cadena NULL arrojar excepciones significaría toneladas de controles de código NULL adicionales de defensa cuando se trata de cadenas, que son molestas. Lo siento, pero estoy de acuerdo con cómo C# .NET maneja esto. ¿Java no hace lo mismo?


Si desea comprobar si una cadena contiene un valor a continuación, utilizar String.IsNullOrEmpty(myString); o String.IsNullOrWhitespace(myString); (sólo en .NET 4.0)

-2

En realidad esto es cómo se representan las cadenas .... nada malo allí. null se utiliza como un carácter de terminación.

Por ejemplo:

cadena de un: "blahblah [nula]" Así que lo lee la cadena sabe que parar en nulo.

entonces cuando creas una cadena como esta: cadena b: "[nulo]" es perfectamente válida.

Ahora, no hay caracteres antes de nulo. entonces, cuando su programa comienza a leer la cadena, encuentra nulo (perfectamente válido) y se detiene ... así ... ¡cadena vacía!

+2

acctually para C# esto es técnicamente incorrecto, creo. En c son terminados nulos, en C# el CLR cuenta cuántos bytes utiliza la cadena y su ubicación. –

+2

No solo no es la forma en que C# almacena cadenas, sino que toda la explicación incluso para C es bastante incorrecta, confundiendo la representación de 'NULL' /' null' para _ "punteros" _ en lenguajes como C/C++/C# con el ASCII ** nul ** _character_, ''\ 0''. – JonBrave

1

Al pensar en la decisión de diseño que se tomó, no solo deberíamos mirar al operador plus de Strings sino también a las clases y métodos relacionados, p. String.Concat(String, String) y StringBuilder.Append(String). Esas clases son parte de Base Class Library que se usan ampliamente en otros idiomas (por ejemplo, Visual Basic y F #).

Desde la perspectiva del diseño del lenguaje y la plataforma, todos esos métodos deben comportarse en una facción uniforme (es decir, tratar nulo de la misma manera). Veo tres opciones posibles:

  • Throw excepción

    Esta es una solución "segura", ya que no está claro qué hacer con nula. Como compensación, requeriría un estilo de programación más defensivo y un código más detallado.

  • Utilice alguna representación de nulo, p. <null>, null o [null] (estilo Java)

    Este es un resultado que esperaba. No está claro por qué debería suceder esto y cómo debe representarse exactamente nulo.

  • Treat nula de la misma manera como cadena vacía (al estilo de .NET)

    La idea detrás de esto es que la representación textual de nulo (es decir, un objeto que falta) es una cadena vacía. En ese caso, un programador puede explotar este comportamiento y escribir un código más corto. Por otro lado, puede ocultar errores.

Hubo que tomar alguna decisión y creo que no hay una opción obvia. El comportamiento esperado en C# y otros lenguajes .NET está claramente documentado y es consistente en todos los métodos que tratan con la concatenación.

Cuestiones relacionadas