Saltar al contenido

Variable Not Found, el blog de José M. Aguilar

el blog de José M. Aguilar

Inicio Perfil Contactar

Artículos, noticias, curiosidades, reflexiones... sobre el mundo del desarrollo
de software, internet, u otros temas relacionados con la tecnología

jueves, octubre 25, 2007

Comprobar si una variable de tipo string está vacía es una tarea que seguro realizamos muy a menudo en nuestras aplicaciones. Observando código, tanto propio como ajeno, he visto que existen varias formas de hacerlo, y a veces cometemos errores que pueden ser fácilmente evitables prestando un poco de atención.

Por ejemplo, dada una variable str declarada como string, utilizando en C# la expresión str.Equals("") podemos conocer si str contiene una cadena vacía. Sin embargo, si str contiene un valor nulo (lo cual es perfectamente posible al tratarse de un tipo referencia) se provocará una excepción de tipo System.NullReferenceException, puesto que estamos intentando llamar a un método de un objeto inexistente.

Ocurre lo mismo si intentamos averiguar el número de caracteres que contiene: (str.Length==0) es cierto si la cadena está vacía, pero igualmente revienta si se trata de un valor nulo.

Una posible solución es preguntar previamente si la cadena es nula y sólo en caso contrario preguntar, siguiendo alguno de los dos patrones descritos anteriormente, si se trata de un string vacío, algo así:
((str!=null) && (str.Length==0))
.

Como podéis observar, aunque válido, parece demasiado laborioso para los que tenemos prisa. Otra forma más corta e ingeniosa de poner lo mismo sería la siguiente: "".Equals(str). Como podéis ver, el problema del nulo desaparece, puesto que se llama al método Equals de la cadena constante "" que siempre tiene valor (la cadena vacía).

Sin embargo, cualquiera de los casos anteriormente citados pueden no funcionar correctamente si consideramos los nulos como una forma más de expresar una cadena vacía. Por ejemplo, observad el siguiente código:


private string saludar(string nombre)
{
if ("".Equals(nombre))
return "No saludo a nadie";
else
return "Hola, " + nombre;
}
 

La función retorna el literal "No saludo a nadie" cuando le llega un nombre vacío (""). Sin embargo, si le llega un valor nulo no se cumple la primera igualdad, entraría en el bloque else y retornaría un saludo absurdo, "Hola, ". Y es que hay veces donde semánticamente el nulo y la cadena vacía son idénticos.

Para estos casos es conveniente hacer equivalentes ambos valores, de forma que nuestra función se comporte exactamente igual tanto si recibe un nulo como si le llega un string vacío. Veamos algunas formas de conseguirlo.

Una fórmula que he visto alguna vez consiste en sumar a nuestro string una cadena vacía en algún momento del proceso, es decir, usar algo como: ""+str. Esta expresión devolverá siempre un string vacío o con el valor original de la variable str, pero nunca un nulo. Una vez realizada esta operación, podemos hacer la comparación con .Equals("") o .Length==0, aunque se recomienda este último por su mejor rendimiento.

Otra forma, algo mejor que la anterior, es usar dos comparaciones combinadas con OR: ((str == null) || (str.Equals(String.Empty))). Así, si str es nulo la expresión evalúa a cierto y sólo en caso contrario se realizará la comparación con la cadena vacía (String.Empty es lo mismo que el string "").

Pero sin duda la mejor opción sería usar el método estático introducido en la clase string en la versión 2.0 de la plataforma: string.IsNullOrEmpty(). Siguiendo con el ejemplo anterior, podríamos reescribirlo de la siguiente manera, consiguiendo el efecto deseado:

private string saludar(string nombre)
{
if (string.IsNullOrEmpty(nombre))
return "No saludo a nadie";
else
return "Hola, " + nombre;
}
 
Este sería un buen momento para dar por finalizado el post si no fuera por que existe un inconveniente a este método, algo que puede parecer increíble: en el framework de Microsoft IsNullOrEmpty() puede hacer que tu aplicación reviente en tiempo de ejecución en las versiones de producción (release) de los ensamblados debido a una mala optimización del JIT cuando utilizamos este método dentro de un bucle. No daré más detalles pues hay multitud de páginas hablando del problema (como VTortola, o El Bruno), pero aquí se aconsejan alternativas a utilizar. En fin, que este método, según se lee, debe ser usado con precaución, o incluso evitado si lo pensamos incluir en un bucle.

Llegados a este punto, por tanto, lo aconsejable es quedarnos con fórmulas artesanales como ((str == null)||(str.Length==0), hasta que IsNullOrEmpty esté en condiciones de ser utilizado, podemos suponer que en la próxima versión de la plataforma.

No he comprobado si existe el mismo problema sobre la plataforma Mono, pero dado que son implementaciones distintas lo más probable es que no ocurra, por lo que IsNullOrEmpty podría ser utilizado sin causar dolores de cabeza. A ver si un día tengo un ratillo y lo compruebo.

Hay que ver lo que da de sí una cosa tan simple, ¿eh?

2 Comentarios:

Leonardo Micheloni

Hola José,
Excelente el post como de costumbre. Yo creo que este tipo de cosas son las que diferencian a los grandes desarrolladores del promedio, ya que demuestran un interés por el detalle, un conocimiento más fino de la herramienta, y hacen que el resultado final sea una aplicación de mayor calidad, solidez y rendimiento. Gracias por otro excelente aporte a la comunidad de habla hispana.

José M. Aguilar

Comentarios así son los que hacen que todo esto valga la pena. :-)

Muchas gracias, Leonardo.