Archivo

Archivos de la categoria ‘.Net’

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 ,

El Tipo Lazy en .Net 4.0

Lunes, 25 de junio de 2012

Todo buen programador necesita un poco de pereza. Algo que le lleve a intentar escribir poco, a no repetirse, a hacer las cosas cada día mejor y a no caer en tareas repetitivas. Últimamente el código “vago” también está en boca de todos, ya sean clases que no se inicializan hasta que se usan o consultas a la BBDD que no se lanzan hasta el último momento.

Tradicionalmente, cuando teníamos una dependencia con una inicialización pesada y que además no sabíamos si se iba o no a ejecutar, hacíamos algo parecido a esto:

//C#

     private Dependencia _Fdependencia;
     private Dependencia _Dependencia
     {
        get { return _Fdependencia ?? (_Fdependencia = new Dependencia()); }
        set { _Fdependencia = value; }
     }
'VB.NET
     private  _Fdependencia as Dependencia
     private Property _Dependencia as Dependencia
        get
          If IsNothing(_Fdependencia) Then _Fdependencia = New Dependencia()
          Return _Fdependencia
        End Get
        Set(value As Dependencia)
           _Fdependencia = value
        End Set
     End Property

Pero desde el lanzamiento del framework 4.0, diponemos del tipo Lazy<> que se ocupa del trabajo por nosotros. En este ejemplo la propiedad no se inicializará hasta que se use por primera vez.

 

//C#
private Lazy<Dependencia> _Dependencia { get; set; }
'VB.NET
private property  _Dependencia as Lazy(Of Dependencia)

En ocasiones no se trata de llamar simplemente a un constructor, sino que el proceso de inicialización de la dependencia puede ser más complejo, requiriendo quizá la llamada a un método:

 

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(InicializarDependencia);
private static Dependencia InicializarDependencia()
{

     //hacer cosas
     return new Dependencia();

}
private  _Dependencia as Lazy(Of Dependencia) = new Lazy(Of Dependencia)(AddressOf InicializarDependencia)
private shared Function  InicializarDependencia() As Dependencia 
     'hacer cosas
     return new Dependencia()
End Function

O si lo preferimos podemos usar expresiones lambda para conseguir esto mismo:

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(()=>
          {
           //hacer cosas
           return  new Dependencia();
          });

 

        private property _Dependencia as Lazy(Of Dependencia)  =new Lazy(Of Dependencia)(function()
                                'hacer cosas
                                 Return New Dependencia
                                 End Function)

En todos estos casos, el proceso de inicialización solo se llevará a cabo al usar la propiedad (o campo) y solo la primera vez.  Para acceder al “tipo interno” lo hacemos mediante la propiedad Value. Es decir, que si queremos llamar al método Metodo1 de _Dependencia lo que haremos es _Dependencia.Value.Metodo1.

Así mismo, el constructor de Lazy<> dispone de una sobrecarga para indicarle si queremos que sea Thread-Safe. (por defecto es true):

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(InicializarDependencia,false);
'VB.NET
private  _Dependencia as Lazy(Of Dependencia) = new Lazy(Of Dependencia)(lazythreadsafetymode.PublicationOnly)

También tenemos sobrecargas para indicarle el tipo de Thread-Safe que queremos que se aplique:

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(InicializarDependencia,LazyThreadSafetyMode.PublicationOnly);
'VB.NET
private  _Dependencia as Lazy(Of Dependencia) = new Lazy(Of Dependencia)(lazythreadsafetymode.PublicationOnly)

Pronto veremos como hacer casar todo esto con conceptos como inversión de control, mientras, como ejemplo de uso, os recomiendo este enlace de John Skeet sobre del patrón Singleton que finaliza en una implementación usando Lazy<> John Skeet Singleton.

.Net

Tipo de dato Tupla en .Net

Jueves, 23 de febrero de 2012

En .Net una tupla es un tipo de dato que representa exactamente lo mismo que en el ambito matemático: Una secuencia o lista de un número concreto de objetos. El tipo tupla se ha integrado en el framework 4.0.

El manejo de tuplas es bien sencillo.  Si quisiéramos crear una tupla de tres elementos (una cadena, un entero y una clase propia, por ejemplo) y luego acceder a ellos lo haríamos de la siguiente manera.

//C#
 //clase propia
 var myInstance = new myclass();

 //creando una tupla de tres elementos
Tuple<string, int, myclass> myTuple = Tuple.Create("Valor", 1, myInstance);

//accediendo a los elementos de una tupla
Console.WriteLine(myTuple.Item1);
Console.WriteLine(myTuple.Item2);
Console.WriteLine(myTuple.Item3);
'VB.Net
'clase propia
Dim myInstance As New CustomClass()

'creando una tupla de tres elementos
Dim myTuple As Tuple(Of String, Integer, CustomClass) = Tuple.Create("Valor", 1, myInstance)

'accediendo a los elementos de una tupla
Console.WriteLine(myTuple.Item1)
Console.WriteLine(myTuple.Item2.ToString)
Console.WriteLine(myTuple.Item3.ToString)

Como podéis ver, el acceso a los miembros de la tupla se hace mediante item1, item2… item X, y podemos crear tuplas de hasta 8 elementos, pero ¿Para que nos puede servir realmente una tupla? Pues imaginemos que tenemos que empaquetar información de alguna manera para luego procesar esa información. Lo más habitual es crear una clase, pero en ocasiones esa información no está directamente relacionada entre sí y además se va a usar en un solo lugar, por lo que no queremos crear una nueva clase. En ese momento, las tuplas pueden echarnos una mano. Si necesitamos que un método retorne varios valores, una tupla es una de las muchas formas de conseguirlo.

¿Se te ocurren muchas situaciones en las que usar una tupla? Si es así, mal vamos. Recuerda el refrán: “A un tonto con un martillo, del cielo le caen los clavos”.  No hay que ser vago, si tienes que devolver un conjunto de datos relacionados, lo mejor es usar una clase. Si tienes dudas, crea una clase. Está bien usar una tupla para que métodos privados retornen datos localizados dentro de clases. Datos que no se van a exponer y a los que incluso te costaría poner un nombre porque no están fuertemente ligados.

Un método público nunca debería retornar una tupla. Piensa que el uso de estos tipos de datos hace que el código no sea autodocumentado. Item1, Item2…ItemX no son precisamente lo que llamaríamos nombres descriptivos. Nos obligarán a poner comentarios indicando qué es cada cosa.

Como curiosidad. ¿No podemos conseguir lo mismo usando tipos anónimos? Pues la verdad es que sí, podemos empaquetar los datos necesarios en un tipo anónimo y luego procesarlos.

Puede que estéis pensando “Ya, pero ¿Cómo retorno un tipo anónimo?” Bueno… lo primero que debo decirte es que nunca deberías retornar un tipo anónimo. Ni siquiera de un método privado y mucho menos de uno público. Además hacerlo es un poco artificial, pero… “Cuando un buen programador está decidido a hacer las cosas mal, ninguna dificultad técnica puede detenerlo”.

//C#
private void ejemplo()
{
    object o = DameUnTipoAnonimo();
    var tipoAnonimo = Cast(o, new { Nombre="", Apellido="" });
    MessageBox.Show(tipoAnonimo.Nombre + " " + tipoAnonimo.Apellido);
}

private object DameUnTipoAnonimo()
{
    return new {Nombre="Jonathan",Apellido="Fernández"};
}

private T Cast<T>(object obj, T type)
{
    return (T)obj;
}
'VB.Net
Private Sub Ejemplo()
    Dim o As Object = DameUnTipoAnonimo()
    Dim tem = New With {.Nombre = "", .Apellido = ""}
    Dim tpo = tem.GetType
    Dim tipoanonimo = CTypeDynamic(o, tpo)
    MessageBox.Show(tipoanonimo.Nombre + " " + tipoanonimo.Apellido)
End Sub

Private Function DameUnTipoAnonimo() As Object
    Return New With {.Nombre = "Jonathan", .Apellido = "Fernández"}
End Function

También tiene su ciencia eso de crear una lista de tipos anónimos:

//C#
private void Ejemplo()
{
    var tipoAnonimo = new { Nombre = "Jonathan", Apellido = "Fernández" };
    var tipoAnonimoList = (new[] { tipoAnonimo }).ToList();
    tipoAnonimoList.Add(new { Nombre = "Kirill", Apellido = "Osenkov" });
    //Kirill Osenkov es el autor de un post en él que ví este ejemplo.
}
'VB.Net
Private Sub Ejemplo()
	Dim tipoAnonimo = New With {.Nombre = "Jonathan", .Apellido = "Fernández"}
	Dim listaTipoAnonimo = CrearListaDesdeElemento(tipoAnonimo)
	listaTipoAnonimo.Add(New With {.Nombre = "Kirill", .Apellido = "Osenkov"})
End Sub

Public Function CrearListaDesdeElemento(Of T)(ByVal p1 As T) As List(Of T)
	Dim lista As New List(Of T)
	lista.Add(p1)
	Return lista
End Function

Con estos ejemplos de código que no deberían ser usados espero haber mostrado que los tipos anónimos no son una buena alternativa a las tuplas, pero volviendo al principio… las tuplas están ahí para ser usadas, pero su uso debe ser moderado y es probable que si aparece la necesidad de usarlas debamos platearnos si estamos haciendo las cosas bien.

.Net ,