el Guille, la Web del Visual Basic, C#, .NET y más...

Tipos anulables (en VB y C# 2005)

 
Publicado: 14/Abr/2006
Actualizado: 14/Abr/2006
Autor: Guillermo 'guille' Som

Aquí te explico que son los tipos anulables, los cuales permiten tener valores normales además de valores nulos, algo muy útil para manejar valores al estilo de como lo hacen las bases de datos. También te explico cómo usar unos tipos anulables definidos por nosotros (en realidad por mi) y de paso cómo usar los tipos anulables de C# 2.0.



 

Introducción

Los tipos anulables están basados en el tipo genérico Nullable(Of T) (en C# Nullable<T>).
Esos tipos además de admitir un valor, permiten que contengan un valor nulo, de esa forma, podemos hacer lo mismo que ocurre en las bases de datos: cuando el valor de un campo no está asignado el valor que tiene es nulo, y como sabes, un valor nulo es... ¡nada! (Nothing en VB o null en C#). Por tanto con los valores nulos no podemos operar.

Pero los tipos Nullable(Of T) permiten hacer ciertas cosas, por ejemplo, podemos obtener el valor que tiene por medio de la propiedad de solo lectura Value, pero debido a que es posible que el tipo no contenga un valor, antes de hacerlo deberíamos comprobar si tiene o no un valor, esto lo conseguimos por medio de la propiedad también de solo lectura: HasValue, esta propiedad devolverá un valor verdadero o falso según la variable tenga o no un valor. O lo que es lo mismo, si devuelve False es que tiene un valor nulo.
Estos tipos de datos tienen un método con el que podemos obtener el valor que contienen o bien un valor por defecto, (para el caso de que no esté asignado), esto lo hacemos por medio del método GetValueOrDefault, el cual tiene dos sobrecargas, una sin parámetros, en la que si no está asignado (es nulo), devolverá el valor por defecto del tipo que representa T, es decir, el tipo que hemos indicado al crearlo, pero también tiene otra sobrecarga en la que podemos indicar el valor por defecto que queramos que devuelva en caso de que el contenido sea nulo, ese valor debe ser del mismo tipo que el "subyacente" o sea del mismo tipo que indicamos al crearlo.

Veamos un par de ejemplos para que sepas de que va todo esto:

Para definir un tipo anulable del subtipo Integer, lo haremos así:

Dim i3 As Nullable(Of Integer)

 

También podemos asignarle un valor al declarar la variable, el cual puede ser un valor "real" o un valor nulo, aunque esto último no es necesario ya que por defecto ese es el valor que tienen los Nullable no inicializados.

Dim i2 As Nullable(Of Integer) = 10

 

Pero si queremos que quede claro que ese es el valor que tiene, pues mejor...

Dim i1 As Nullable(Of Integer) = Nothing

 

El problema de los tipos anulables es que no podemos trabajar con ellos directamente, al menos no podemos hacer las operaciones que nos permite el tipo usado como "base" del tipo anulable.
Por ejemplo, si intentamos hacer operaciones con ellos, dará error:

i3 = i2 + 10

Para que no de error, debemos usar el "valor interno", (recuerda que lo conseguimos con la propiedad Value):

i3 = i2.Value + 10

Y como puedes comprobar, ese valor en realidad es un valor del mismo tipo usado en la definición, por tanto lo podemos usar para operar con otros tipos de datos que "sepan operar con ese tipo".

El problema que nos podemos encontrar es que cualquiera de los tipos anulables que intervengan en la expresión contengan un valor nulo, ya que en ese caso, recibiremos un bonito error indicando que "nones", que no se puede operar con valores nulos, y esto es así tengamos o no Option Strict On (ya sabes que si no usas Option Strict On ¡no te ajunto!).

La solución es usar el método GetValueOrDefault, de esa forma, nos aseguramos de que siempre estemos usando un valor "válido":

i3 = i1.GetValueOrDefault() + i2.GetValueOrDefault()

 

Para solventar estos "problemillas", he creado una librería (DLL) en Visual Basic 2005 en la que he definido tipos "anulables" de fácil utilización, de forma que las variables se comporten como tipos normales y al mismo tiempo como tipos anulables, es decir, permiten trabajar con valores nulos, pero he definido sobrecargas de los operadores aritméticos y relacionales para que sea más fácil hacer las operaciones que normalmente hacemos.
Incluso si usamos valores nulos, estos funcionarán sin darnos error.

Aquí te muestro el mismo ejemplo que antes, pero usando el tipo IntegerNullable definido en la DLL del link anterior, y la salida que produce:

 

Console.WriteLine("Pruebas con tipos IntegerNullable")
Console.WriteLine("=================================")
Dim i1 As IntegerNullable = Nothing
Dim i2 As IntegerNullable = 10
Dim i3 As IntegerNullable

Console.WriteLine("i1 = {0,6}, i1.HasValue = {1}", i1, i1.HasValue) ' False
Console.WriteLine("i2 = {0,6}, i2.HasValue = {1}", i2, i2.HasValue) ' True
Console.WriteLine("i3 = {0,6}, i3.HasValue = {1}", i3, i3.HasValue) ' False

Console.WriteLine()
' Podemos operar directamente con los tipos anulables de la librería
i3 = i2 + 10
Console.WriteLine("i3 = i2 + 10 := {0}", i3)

Console.WriteLine()
' Así como con los valores por medio de Value
i3 = i2.Value + 10
Console.WriteLine("i3 = i2.Value + 10 := {0}", i3)

Console.WriteLine()
' Y con variables del mismo tipo
i3 = i1 + i2

' Si uno de los tipos anulables contiene Nothing el resultado también
Console.WriteLine("Al hacer: i3 = i1 + i2")
Console.WriteLine("Como i1 es Nothing, obtenemos Nothing:")
Console.WriteLine("i1 = {0}, i2 = {1}, i3 = {2}", i1, i2, i3)
' 
Console.WriteLine()
i3 = i1.Value + i2.Value
Console.WriteLine("i3 = i1.Value + i2.Value := {0}", i3)

Console.WriteLine()
' Podemos usar GetValueOrDefault para que siempre tengan un valor
i3 = i1.GetValueOrDefault() + i2.GetValueOrDefault()
Console.WriteLine("i3 = i1.GetValueOrDefault() + i2.GetValueOrDefault() := {0}", i3)

La salida es:


Pruebas con tipos IntegerNullable
=================================
i1 = Nothing, i1.HasValue = False
i2 = 10, i2.HasValue = True
i3 = Nothing, i3.HasValue = False

i3 = i2 + 10 := 20

i3 = i2.Value + 10 := 20

Al hacer: i3 = i1 + i2
Como i1 es Nothing, obtenemos Nothing:
i1 = Nothing, i2 = 10, i3 = Nothing

i3 = i1.Value + i2.Value := 10

i3 = i1.GetValueOrDefault() + i2.GetValueOrDefault() := 10
 

 

 

Cómo usar los tipos anulables en C#

Ni que decir que todo esto con C# se hace de forma "natural", es decir, sin tener que definir nada especial, ya que a partir de la versión 2.0 de .NET (C# 2.0) ya tiene tipos anulables definidos, los cuales se usan como los tipos normales, pero seguidos de una interrogación, por ejemplo: int? es el tipo anulable basado en int.

Nota:
Por supuesto, en C# también puedes usar los tipos Nullable<T>, pero como ya tiene sus propios tipos... ¿para qué?

El mismo ejemplo de antes lo podemos hacer en C# de esta forma:
(fíjate que int? no permite operar con valores nulos, al menos si usamos la propiedad Value para obtener el valor).

 

Console.WriteLine("Pruebas con tipos int?");
Console.WriteLine("======================");
int? i1 = null;
int? i2 = 10;
int? i3 = null; // en C# hay que asignarle algo antes de usarla

Console.WriteLine("i1 = {0,6}, i1.HasValue = {1}", i1, i1.HasValue); // False
Console.WriteLine("i2 = {0,6}, i2.HasValue = {1}", i2, i2.HasValue); // True
Console.WriteLine("i3 = {0,6}, i3.HasValue = {1}", i3, i3.HasValue); // False

Console.WriteLine();
// Podemos operar directamente con los tipos anulables de la librería
i3 = i2 + 10;
Console.WriteLine("i3 = i2 + 10 := {0}", i3);

Console.WriteLine();
// Así como con los valores por medio de Value
i3 = i2.Value + 10;
Console.WriteLine("i3 = i2.Value + 10 := {0}", i3);

Console.WriteLine();
// Y con variables del mismo tipo
i3 = i1 + i2;

// Si uno de los tipos anulables contiene Nothing el resultado también
Console.WriteLine("Al hacer: i3 = i1 + i2");
Console.WriteLine("Como i1 es Nothing, obtenemos Nothing:");
Console.WriteLine("i1 = {0}, i2 = {1}, i3 = {2}", i1, i2, i3);
//
Console.WriteLine();
// En C# esto dará una excepción
// porque i1.Value es null
//i3 = i1.Value + i2.Value;
//Console.WriteLine("i3 = i1.Value + i2.Value := {0}", i3);

Console.WriteLine();
// Podemos usar GetValueOrDefault para que siempre tengan un valor
i3 = i1.GetValueOrDefault() + i2.GetValueOrDefault();
Console.WriteLine("i3 = i1.GetValueOrDefault() + i2.GetValueOrDefault() := {0}", i3);

 

 

Espero que todo esto te haya aclarado un poco de que va esto de los tipos anulables y de cómo usarlos tanto desde Visual Basic 2005 como desde C# 2005.

¡Que lo anules bien!

Nos vemos
Guillermo



 


La fecha/hora en el servidor es: 22/12/2024 17:42:35

La fecha actual GMT (UTC) es: 

©Guillermo 'guille' Som, 1996-2024