Inicialización de cadena predeterminada: NULL o Empty? [cerrado]

130

Siempre he inicializado mis cadenas a NULL, con el pensamiento de que NULL significa la ausencia de un valor y "" o String.Empty es un valor válido. Últimamente he visto más ejemplos de código donde String.Empty se considera el valor predeterminado o no representa ningún valor. Esto me parece extraño, con los tipos anulables recién agregados en c # parece que estamos avanzando hacia atrás con cadenas al no usar NULL para representar 'Sin valor'.

¿Qué utiliza como inicializador predeterminado y por qué?

Editar: Basado en las respuestas, sigo pensando más

  1. Evitar el manejo de errores Si el valor no debe ser nulo, ¿por qué se configuró NULLen primer lugar? ¿Quizás sería mejor identificar el error en el lugar donde ocurre en lugar de ocultarlo en el resto de su código base?

  2. Evitar verificaciones nulas Si está cansado de hacer verificaciones nulas en el código, ¿no sería mejor abstraer las verificaciones nulas? ¿Quizás envolver (o extender) los métodos de cadena para hacerlos NULLseguros? ¿Qué sucede si usa constantemente String.Emptyy sucede que un valor nulo funciona en su sistema? ¿Comienza a agregar NULLcheques de todos modos?

No puedo evitar volver a la opinión de que es pereza. Cualquier DBA te abofetearía nueve formas de hacer el tonto si usaras '' en lugar de nullen su base de datos. Creo que los mismos principios se aplican en la programación y debería haber alguien para golpear a aquellos que usan en String.Emptylugar de NULLno representar ningún valor.

preguntas relacionadas

vfilby
fuente
¿'El cuerdo'? No debe ser un Dana, lo sé.
vfilby
@Joel, estoy sorprendido por la cantidad de personas que no tienen idea sobre Zim o GIR. También estoy sorprendido por algunos de mis amigos que lo encuentran repulsivo. No digo que sea pura bondad, pero hay pepitas de humor increíbles allí.
vfilby
Lo sé, pero a veces es divertido fingir lo contrario.
Dana the Sane
1
Me encontré con este problema en colecciones de formularios MVC o variables de sesión mucho, encontré que lo más útil era convertir nulo a String. taquigrafía, y luego aplique cualquier operación de cadena requerida. p.ej. (item ?? String.Empty) .Trim (). ToUpper ()
sonjz
44
esto no es constructivo?
nawfal

Respuestas:

111

+1 para distinguir entre "vacío" y NULL. Estoy de acuerdo en que "vacío" debería significar "válido, pero en blanco" y "NULO" debería significar "inválido".

Entonces respondería tu pregunta de esta manera:

vacío cuando quiero un valor predeterminado válido que pueda o no cambiarse, por ejemplo, el segundo nombre de un usuario.

NULL cuando es un error si el código resultante no establece el valor explícitamente.

Adam Liss
fuente
11
Distinguir entre NULL y empty es genial cuando en realidad hay una diferencia entre los dos. Sin embargo, hay muchos casos en los que no hay diferencia y, por lo tanto, tener dos formas de representar lo mismo es una responsabilidad.
Greg Smalter
66
@Greg: Si bien estoy de acuerdo en que la variedad tiene el potencial de confusión, también puede ser un gran activo. La convención simple y consistente de escribir "" o NULL para diferenciar entre valores válidos e inválidos hará que su código sea más fácil de entender. Es por eso que siempre pruebo booleanos con "if (var)", punteros con "if (var! = NULL)" y enteros con "if (var! = 0)": todos significan lo mismo para el compilador, pero llevan información adicional que ayuda al desarrollador pobre que mantiene mi código.
Adam Liss
32

De acuerdo con MSDN :

Al inicializar cadenas con el Emptyvalor en lugar de null, puede reducir las posibilidades de que NullReferenceExceptionocurra.

IsNullOrEmpty()Sin embargo, usar siempre es una buena práctica.

Tomalak
fuente
45
El hecho de que esté reduciendo las posibilidades de la excepción no significa que la excepción no deba estar sucediendo. Si su código depende de un valor, ¡debería arrojar una excepción!
rmeador
1
Claro, no hay discusión allí. OTOH, si solo está agregando cadenas juntas ... Creo que depende del estilo de codificación, la experiencia y la situación.
Tomalak
Esto es principalmente lo que uso distinguir cuál usar también.
PositiveGuy
3
No olvides IsNullOrWhiteSpace () para .NET framework 4+
Coops
13

¿Por qué quieres que tu cadena se inicialice? No tiene que inicializar una variable cuando declara una, e IMO, solo debe hacerlo cuando el valor que está asignando es válido en el contexto del bloque de código.

Veo esto mucho:

string name = null; // or String.Empty
if (condition)
{
  name = "foo";
}
else
{
  name = "bar";
}

return name;

No inicializar a nulo sería igual de efectivo. Además, lo más frecuente es que desee asignar un valor. Al inicializar a nulo, puede perder rutas de código que no asignan un valor. Al igual que:

string name = null; // or String.Empty
if (condition)
{
  name = "foo";
}
else if (othercondition)
{
  name = "bar";
}

return name; //returns null when condition and othercondition are false

Cuando no inicializa a nulo, el compilador generará un error que dice que no todas las rutas de código asignan un valor. Por supuesto, este es un ejemplo muy simple ...

Matthijs


fuente
En Visual Studio, que creo que casi todos los programadores de C # usan, su segunda situación (sin la = null) generaría una advertencia, exactamente por la razón que usted indicó: no importa si el valor predeterminado de una cadena es nulo. si no garantiza una asignación a través de cada ruta de código, el IDE (y / o supongo que el compilador subyacente [?]) generará una advertencia. Aunque las advertencias no impedirán la compilación, todavía están allí: dejar las que se resuelven fácilmente puede ayudar a ofuscar a otras que pueden merecer la atención del programador
Code Jockey
que yo sepa, la primera situación será perfectamente feliz sin la inicialización de nameto null(sin advertencias), porque cada ruta de código asigna un valor a name, sin necesidad de inicializar allí
Code Jockey
8

Para la mayoría del software que no es realmente software de procesamiento de cadenas, la lógica del programa no debe depender del contenido de las variables de cadena. Cada vez que veo algo así en un programa:

if (s == "value")

Tengo un mal presentimiento. ¿Por qué hay una cadena literal en este método? ¿Qué está configurando s? ¿Sabe que la lógica depende del valor de la cadena? ¿Sabe que tiene que ser minúscula para trabajar? ¿Debería arreglar esto cambiándolo para usarlo String.Compare? ¿Debería crear Enumy analizarlo?

Desde esta perspectiva, uno llega a una filosofía de código que es bastante simple: evita examinar el contenido de una cadena siempre que sea posible. Comparar una cadena String.Emptyes realmente solo un caso especial de compararla con un literal: es algo que debe evitarse a menos que realmente tenga que hacerlo.

Sabiendo esto, no parpadeo cuando veo algo así en nuestra base de código:

string msg = Validate(item);
if (msg != null)
{
   DisplayErrorMessage(msg);
   return;
}

Sé que eso Validatenunca volvería String.Empty, porque escribimos un código mejor que eso.

Por supuesto, el resto del mundo no funciona así. Cuando su programa trata con entradas de usuarios, bases de datos, archivos, etc., debe tener en cuenta otras filosofías. Allí, es el trabajo de su código imponer orden en el caos. Parte de ese orden es saber cuándo debería significar una cadena vacía String.Emptyy cuándo debería significar null.

(Solo para asegurarme de que no estaba hablando por el culo, solo busqué en nuestra base de código para 'String.IsNullOrEmpty'. Las 54 ocurrencias están en métodos que procesan la entrada del usuario, devuelven valores de scripts de Python, examinan valores recuperados de API externas, etc.)

Robert Rossney
fuente
6

Esto es en realidad un agujero enorme en el lenguaje C #. No hay forma de definir una cadena que no pueda ser nula. Esto causa problemas tan simples como el que está describiendo, lo que obliga a los programadores a tomar una decisión que no deberían tener que tomar, ya que en muchos casos NULL y String.Empty significan lo mismo. Eso, a su vez, puede obligar a otros programadores a tener que manejar NULL y String.Empty, lo cual es molesto.

Un problema mayor es que las bases de datos le permiten definir campos que se asignan a una cadena de C #, pero los campos de la base de datos se pueden definir como NO NULOS. Por lo tanto, no hay forma de representar con precisión, por ejemplo, un campo varchar (100) NOT NULL en SQL Server utilizando un tipo C #.

Otros idiomas, como Spec #, permiten esto.

En mi opinión, la incapacidad de C # para definir una cadena que no permita nulo es tan mala como su incapacidad previa para definir un int que permita nulo.

Para responder completamente a su pregunta: siempre uso una cadena vacía para la inicialización predeterminada porque es más similar a cómo funcionan los tipos de datos de la base de datos. (Editar: Esta declaración no estaba muy clara. Debería leer "Uso una cadena vacía para la inicialización predeterminada cuando NULL es un estado superfluo, de la misma manera que configuré una columna de base de datos como NOT NULL si NULL sería un estado superfluo. De manera similar , muchas de mis columnas de base de datos están configuradas como NOT NULL, por lo que cuando las traigo a una cadena C #, la cadena estará vacía o tendrá un valor, pero nunca será NULL. En otras palabras, solo inicializo una cadena a NULL si nulo tiene un significado que es distinto del significado de String.Empty, y creo que ese caso es menos que común (pero la gente aquí ha dado ejemplos legítimos de este caso) ".

Greg más pequeño
fuente
Usar String.Empty solo es similar a una de las formas en que se define una cadena de base de datos. Usar nulo para representar ningún valor es mucho más congruente con un nvarchar nulo. Creo que cualquier DBA que valga la pena te abofetearía nueve maneras de hacer el tonto si no representaras ningún valor.
vfilby el
En realidad, Greg, lo has entendido mal. Son los tipos de valores no anulables los que menos "cómo funcionan los tipos de bases de datos" porque nunca pueden contener un valor nulo y, por lo tanto, no pueden asignarse a una columna anulable. En el contrato, cualquier cadena puede mapearse a cualquier columna varchar.
Tor Haugen el
Tienes razón, mi última afirmación no fue lo suficientemente clara. La mayoría de las veces, las columnas de mi base de datos NO SON NULAS (porque no habría diferencia entre el significado de cadena vacía y NULL), por lo que intento mantener mis cadenas similares sin almacenar nunca nulas en ellas, y eso es lo que quise decir.
Greg Smalter
5

Depende.

¿Necesita saber si falta el valor (es posible que no se defina)?

¿Es la cadena vacía un valor válido para el uso de esa cadena?

Si respondió "sí" a ambas, entonces querrá usar nulo. De lo contrario, no puede distinguir la diferencia entre "sin valor" y "cadena vacía".

Si no necesita saber si no hay valor, entonces la cadena vacía es probablemente más segura, ya que le permite omitir las verificaciones nulas donde sea que la use.

Herms
fuente
3

Lo configuro en "" o nulo; siempre verifico usando String.IsNullOrEmpty, por lo que está bien.

Pero el geek interno en mí dice que debería configurarlo como nulo antes de tener un valor adecuado para él ...

Codificador Quirúrgico
fuente
3

Siempre declaro cadena con string.empty;

Ervin Ter
fuente
2

¿Es posible que esta sea una técnica para evitar errores (aconsejable o no ...)? Dado que "" sigue siendo una cadena, ¿podría invocar funciones de cadena que darían lugar a una excepción si fuera NULL?

Dana la sana
fuente
1
Esa es la excusa que normalmente escucho, solo suena a pereza. "No quiero molestarme en comprobar este valor, así que voy a tomar un atajo", me parece a mí.
vfilby
Sí, no estoy en desacuerdo. Puede haber algunas situaciones en las que reducir la cantidad de código de comprobación de errores es bueno, pero las llamadas a funciones que no tienen ningún efecto tampoco son las mejores ...
Dana the Sane
2

Siempre los inicializo como NULL.

Yo siempre utilizo string.IsNullOrEmpty(someString)para comprobar su valor.

Sencillo.

Pure.Krome
fuente
1

Depende de la situación. En la mayoría de los casos, uso String.Empty porque no quiero hacer comprobaciones nulas cada vez que intento usar una cadena. Hace que el código sea mucho más simple y es menos probable que introduzca bloqueos NullReferenceException no deseados.

Solo configuro la cadena en nulo cuando necesito saber si se ha configurado o no y dónde una cadena vacía es algo válido para establecerla. En la práctica, encuentro estas situaciones raras.

Rob Prouse
fuente
1

Una cadena vacía es un valor (un fragmento de texto que, por cierto, no contiene letras). Nulo significa sin valor.

Inicializo variables a nulo cuando deseo indicar que no apuntan o no contienen valores reales, cuando la intención es sin valor.

Yfeldblum
fuente
1

Reiterando la respuesta de Tomalak, tenga en cuenta que cuando asigna una variable de cadena a un valor inicial de nulo, su variable ya no es un objeto de cadena; lo mismo con cualquier objeto en C #. Entonces, si intenta acceder a cualquier método o propiedad para su variable y está asumiendo que es un objeto de cadena, obtendrá la excepción NullReferenceException.

Michael Ritchson
fuente
1

Nulo solo debe usarse en casos donde un valor es opcional. Si el valor no es opcional (como 'Nombre' o 'Dirección'), el valor nunca debe ser nulo. Esto se aplica tanto a las bases de datos como a los POCO y la interfaz de usuario. Nulo significa "este valor es opcional y actualmente está ausente".

Si su campo no es opcional, debe inicializarlo como la cadena vacía. Inicializarlo como nulo colocaría su objeto en un estado no válido (inválido por su propio modelo de datos).

Personalmente, prefiero que las cadenas no sean anulables de forma predeterminada, sino que solo se anulan si declaramos una "cadena". Aunque quizás esto no sea factible o lógico a un nivel más profundo; no estoy seguro.

Dave Cousineau
fuente
0

Las cadenas no son tipos de valor, y nunca lo serán ;-)

Tor Haugen
fuente
0

Creo que no hay razón para no usar nulo para un valor no asignado (o en este lugar en un flujo de programa que no ocurre). Si desea distinguir, hay == nulo. Si solo desea verificar un cierto valor y no le importa si es nulo o algo diferente, String.Equals ("XXX", MyStringVar) funciona bien.

Volker
fuente