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