Archivo

Posts con el Tag ‘Valores por defecto’

Diferencias en nulos y valores por defecto entre C# y Vb.Net

Domingo, 27 de enero de 2013

En muchas ocasiones un programador habituado a Vb.net debe saltar a C#, (e incluso algún caso se ha dado en que el programador debe recorrer el camino contrario). Realizar el cambio no es complicado.

Hoy voy a hablar de algo muy de base: ¿Qué deferencias existen a la hora de tratar los valores nulos entre ambos lenguajes? Muchas no, pero alguna hay y merece la pena comentar como se trata el tema en ambos.

Comenzando por Vb.Net, nos encontramos con dos posibles formas de ver si una variable es nula: Variable Is nothing… o IsNothing(variable)

A primera vista ambos tienen el mismo comportamiento… pero solo a primera vista. Cuando ejecutamos el código variable Is Nothing y el tipo de nuestra variable es un tipo valor (value type) el código no compilará (Error: El operando de esta función debe ser un tipo referencia o un tipo nulable). En cambio si usamos la sintaxis IsNothing(Variable) no se producirá ningún tipo de error de compilación, aunque la función siempre devolverá False.

De hecho, lo que está ocurriendo es que el método IsNothing hace un cast a object y luego retorna el resultado de Variable Is Nothing, pero ya siendo la variable de tipo Object. Ojo, he escrito “el método IsNothing” con toda la intención, ya que realmente se está produciendo una llamada a un método implementado en Microsoft.VisualBasic.Information en lugar de resolverse la expresión “in line”.

Por todo lo anterior, parece que IsNothing(variable) es algo a evitar en favor de su alternativa  variable Is nothing ¿No?… pues sí. Punto pelota. No parece haber ninguna situación en que sea mejor usar el método (Y digo parece porque en este mundo, seguro seguro, solo la muerte).  Pero me voy a esforzar… supongamos una clase que usa genericidad como la que expongo:

'Vb.Net
Public Class Generica(Of T)

    Private Property Variable As T

    Public Sub AVerQuePasa()
        Console.WriteLine(Variable Is Nothing)
    End Sub

End Class

Esta clase no sabe de qué tipo es T… y si la declaro siendo T un entero, va a realizar un Is Nothing en tiempo de ejecución teniendo como operando un tipo valor, así que lo mismo al llamar al método, casca ¿No? Pues ya os digo yo que no. Funciona bien.

Demos un breve y agradable salto a C# para ver cómo se toma estas cosas. En C# No hay ningún problema en escribir un código como el siguiente:

int i = 0;
Console.WriteLine(i == null);

Eso sí, si contáis con ReSharper veréis que os advierte de que el resultado siempre será false (Cosa que no hace ReSharper para Vb.Net) Es decir, que esta comparación con Nulo se comporta como Isnothing(), pero con la salvedad de que se resuelve la expresión In Line, sin tener que llamar a un método externo.

En cambio si escribimos lo mismo en Vb.Net:

Dim i as integer= 0
Console.WriteLine(i = nothing)

Parece que funciona, Pero ¿Estamos imprimirendo realmente si el valor es nulo? ¿Hay entonces 3 formas de comprobarlo en lugar de 2? Pues no. No estamos realmente comprobando si la variable i es nula, lo que estamos comprobando es si i tiene su valor por defecto. (Ahí lo llevas) Lo explico:

Esta sentencia es perfectamente legal en Vb.Net:

Dim j As Integer = Nothing

Mientras que no se puede hacer nada parecido en C#, porque ¿No hemos quedado en que es un entero y no un tipo nulable? Pues sí, pero resulta que en Vb.Net cuando asignas Nothing a un tipo valor, lo que en realidad estás haciendo es asignarle su valor por defecto. Lo mismo que hace Default(T) que se usa en C# para genéricos, pero tocando más los… digo más críptico. Esta es la razón por la cual el ejemplo anterior no cuenta como una forma de comparar si una variable es nula.

Este detalle que parece una tontería, nos puede llevar a tirarnos de los pelos, por ejemplo, al trabajar con genericidad y comparar si un tipo tiene el valor por defecto sin saber si el tipo será valor o referencia.

 En C# en una clase genérica, para comprobar que una variable tipo T tiene su valor por defecto, hacemos algo como:

if(EqualityComparer<T>.Default.Equals(variable, default(T)))
{

}

Mientras que en Vb.Net tendríamos que hacer algo así:

If EqualityComparer(Of T).Default.Equals(variable, Nothing) Then

End If

Que aunque no lo parezca a primera vista, resuelve si el objeto tiene su valor por defecto. Es decir que para un T entero y una variable con valor cero, devuelve true, pero si la variable tiene otro valor, retorna false, y para una clase funciona igual de bien.

O, si T no tiene un coste de construcción muy alto, podemos aprovecharnos de que en Vb.Net no tenemos que definir las variables con una expresión y hacer algo más costoso pero más claro:

Dim defaultVar As T    
If variable.Equals(defaultVar) Then
    ''
End If
Y esto es todo por hoy ;)

.Net ,