InicioArticulos y noticiasBases de datosProgramaciónForosInternetServiciosContratacionEmail
Tutorial C#
Introduccion a C#
Programacion con C#
Fundamentos de C#
Operadores
Instrucciones
Estrcuturas de control.
Definición de clases
Creación de objetos
Herencia y métodos virtuales
Polimorfismo
Ocultación de miembros
Miembros de tipo
Encapsulación
Espacios de nombres
Importación de espacios de nombres
Espacio de nombres distribuidos
Variables y tipos de datos
Tablas unidimensionales
Tablas multidimensionales
La clase System.Array
Cadenas de texto
Constantes
Orden de inicialización de variables
Métodos
Métodos externos
Constructores
Destructores
Propiedades
Indizadores
Redefinición de operadores
Delegados y eventos
La clase MulticastDelegate
Llamadas asíncronas
Implementación interna de los delegados
Eventos
Estructuras
Boxing y unboxing
Constructores de estructuras
Enumeraciones
Interfaces
Excepciones
Otras instrucciones
Atributos
Definición de nuevos atributos
Lectura de atributos en tiempo de ejecución
Atributos de compilación
Pseudoatributos
Código inseguro
Definición de punteros
Manipulación de punteros
Operadores relacionados con código inseguro
Fijación de variables apuntadas
Novedades de C# 2.0
Genéricos
Tipos parciales
Iteradores
Mejoras en la manipulación de delegados
Tipos anulables
Modificadores de visibilidad de bloques get y set
Clases estáticas
Referencias a espacios de nombres
Supresión temporal de avisos
Atributos condicionales
Incrustación de tablas en estructuras
Modificaciones en el compilador
También puedes ver ...
Creando cadenas de conexión ConnectionStrings en .net 3.5 o visual Studio 2008 usando SqlConnectionStringBuilder
Migración de WSE a WCF (Web Services de 2005 a 2008)
Generar archivos PDF con C#
TransactionScope - Simplificando el trabajo con transacciones.
LinQ To SQL - Un ejemplo sencillo
Cómo activar Intelisense (autocompletado) en el Web.config
Leer un campo XML de SQL Server 2005 con C#
TripleDES - Un ejemplo practico en C#
Mostrar un GridView dentro de un DataList
String.Format

Afiliados
La Web del programador
MundoProgramacion


 

Tipos anulables

Concepto

    En C# 2.0 las variables de tipos valor también pueden almacenar el valor especial null, como las de tipos referencia. Por ello, a estas variables se les denomina tipos anulables.

    Esto les permite señalar cuando almacenan un valor desconocido o inaplicable, lo que puede resultar muy útil a la hora de trabajar con bases de datos ya que en éstas los campos de tipo entero, booleanos, etc. suelen permitir almacenar valores nulos. Así mismo, también evita tener que definir ciertos valores especiales para los parámetros o el valor de retorno de los métodos con los que expresar dicha semántica (pe, devolver -1 en un método que devuelva la posición donde se haya un cierto elemento en una tabla para indicar que no se ha encontrado en la misma), cosa que además puede implicar desaprovechar parte del rango de representación del tipo valor o incluso no ser posible de aplicar si todos los valores del parámetro o valor de retorno son significativos.

Sintaxis

    La versión anulable de un tipo valor se representa igual que la normal pero con el sufijo ?, y se le podrán asignar tanto valores de su tipo subyacente (el tipo normal, sin el ?) como null. De hecho, su valor por defecto será null. Por ejemplo:


int? x = 1;
x = null;

    En realidad el uso de ? no es más que una sintaxis abreviada con la que instanciar un objeto del nuevo tipo genérico Nullable<T> incluido en el espacio de nombres System de la BCL con su parámetro genérico concretizado al tipo subyacente. Este tipo tiene un constructor que admite un parámetro del tipo genérico T, por lo que en realidad el código del ejemplo anterior es equivalente a:


Nullable<int> x = new Nullable<int>(1);// También valdría
// Nullable<int>x = new int?(1);
x = null;

    El tipo Nullable proporciona dos propiedades a todos los tipos anulables: bool HasValue para indicar si almacena null, y T Value, para obtener su valor. Si una variable anulable valiese null, leer su propiedad Value haría saltar una InvalidOperationException. A continuación se muestra un ejemplo del uso de las mismas:


 using System;
 class Anulables
 {
  static void Main()
  {
   int? x = null;
   int? y = 123;
   MostrarSiNulo(x, "x");
   MostrarSiNulo(y, "y");
  }
  static void MostrarSiNulo(int? x, string nombreVariable)
  {
   if (!x.HasValue)
    Console.WriteLine("{0} es nula", nombreVariable);
   else
    Console.WriteLine("{0} no es nula. Vale {1}.",nombreVariable,x.Value);
  }
 }

    En él, el método MostrarSiNulo() primero comprueba si la variable vale null, para si así simplemente indicarlo y si no indicar cuál su valor. Su salida será:

x es nula

y no es nula. Vale 123.

    En realidad nada fuerza a utilizar HasValue para determinar si una variable anulable vale null, sino que en su lugar se puede usar el habitual operador de igualdad. Del mismo modo, en vez de leer su valor a través de de la propiedad Value se puede obtener simplemente accediendo a la variable como si fuese no anulable. Así, el anterior método MostrarSiNulo() podría rescribirse como sigue, con lo que quedará mucho más legible:


 static void MostrarSiNulo(int? x, string nombreVariable)
 {
  if (x==null)
   Console.WriteLine("{0} es nula", nombreVariable);
  else
   Console.WriteLine("{0} no es nula. Vale {1}.", nombreVariable, x);
 }

    Finalmente, hay que señalar que el tipo subyacente puede ser a su vez un tipo anulable, siendo válidas declaraciones del tipo int??, int???, etc. Sin embargo, no tiene mucho sentido hacerlo ya que al fin y al cabo los tipos resultantes serían equivalentes y aceptarían el mismo rango de valores. Por ejemplo, una instancia del tipo int??? podría crearse de cualquier de estas formas:


 int??? x = 1;
 x = new int???(1);
 x = new int???(new int??(1));
 x = new int???(new int??(new int?(1)));

Y leerse como sigue:


 Console.WriteLine(x);
 Console.WriteLine(x.Value);
 Console.WriteLine(x.Value.Value);
 Console.WriteLine(x.Value.Value.Value);

Conversiones

    C# 2.0 es capaz realizar implícitamente conversiones desde un tipo subyacente a su versión anulable, gracias  alo que cualquier valor del tipo subyacente de una variable anulable se puede almacenar en la misma. Por ejemplo:


int x = 123;
int? y = x;

    Lo que no es posible realizar implícitamente es la conversión recíproca (de un tipo anulable a su tipo subyacente) ya que si una variable anulable almacena el valor null este no será válido como valor de su tipo subyacente. Por tanto, estas conversiones han de realizarse explícitamente, tal y como a continuación se muestra:

 int z = (int) y; 

    Lo que sí se permite también es realizar implícitamente entre tipos anulables todas aquellas conversiones que serían válidas entre sus versiones no anulables. Por ejemplo:


 double d = z;
 double d2 = (double) y;  // Se puede hacer la conversión directamente
// a double
 d2 = (int) y;            // o indirectamente desde int
 z = (int) d;
 y = (int?) d2;           // Se puede hacer la conversión directamente
// a int?
 y = (int) d2;            // o indirectamente desde int

Operaciones con nulos

    Obviamente, la posibilidad de introducir valores nulos en los tipos valor implica que se tengan que modificar los operadores habitualmente utilizados al trabajar con ellos para que tengan en cuenta el caso en que sus operandos valgan null.

    Para los operadores relacionales, esto implicaría en principio la introducción de una lógica trivaluada (valores true, false y null), como en las bases de datos SQL. Sin embargo, en tanto que ello suele atentar contra la intuitividad y provocar "problemas psicológicos" a los programadores, se ha preferido simplificar el funcionamiento de estos operadores y hacer que simplemente devuelvan true si sus dos operadores valen null y false si solo uno de ellos lo hace, pero jamás devolverán null. Por ejemplo:


 int? i = 1;
 int? j = 2;
 int? z = null;
 
 Console.WriteLine(i > j);
// Imprime False, al ser el valor de i menor que el de j
 Console.WriteLine(i > z);
// Imprime False, al ser z null.
 Console.WriteLine(i > null);
// Imprime False. El compilador incluso avisa de que este
// tipo de comparaciones siempre retornan false por ser uno
// de sus operandos null.
 Console.WriteLine(null > null); // Imprime False. Ídem al caso anterior. 

    Sin embargo, para el caso de los operadores lógicos sí que se ha optado por permitir la devolución de null por similitud con SQL, quedando sus tablas de verdad definidas como sigue según esta lógica trivaluada:

x

y

x && y

x || y

true

true

true

true

true

false

false

true

true

null

null

true

false

false

false

false

false

null

false

null

null

null

null

null

Tabla 20: Tabla de verdad de los operadores lógicos en lógica trivaluada

    Y en el caso de los aritméticos también se permite la devolución de null, aunque en este caso su implementación es mucho más intuitiva y simplemente consiste en retornar null si algún operador vale null y operar normalmente si no (como en SQL) Por ejemplo:


 int? i = 1;
 int? j = 2;
 int? z = null;
 Console.WriteLine(i + j);
// Imprime 3, que es la suma de los valores de i y j
 Console.WriteLine(i + z);
// No imprime nada, puesto que i+z devuelve null.

    En cualquier caso, debe tenerse en cuenta que no es necesario preocuparse por cómo se comportarán los operadores redefinidos ante las versiones anulables de las estructuras, pues su implementación la proporcionará automáticamente el compilador. Por ejemplo, si se ha redefinido el operador + para una estructura, cuando se aplique entre versiones anulables del tipo simplemente se mirará si alguno de los operandos es null, devolviéndose null si es así y ejecutándose la redefinición del operador si no.

Operador de fusión (??)

    Para facilitar el trabajo con variables anulables, C# 2.0 proporciona un nuevo operador de fusión ?? que retorna su operando izquierdo si este no es nulo y el derecho si lo es. Este operador se puede aplicar tanto entre tipos anulables como entre tipos referencia o entre tipos anulables y tipos no anulables. Ejemplos de su uso serían los siguientes:


 int z;
 int? enteronulo = null;
 int? enterononulo;
 string s = null;
 z = enteronulo ?? 123; // Válido entre tipo anulable y no anulable. z=123
 enterononulo = enteronulo ?? 123; // enterononulo = 123.
 z = (int) (enteronulo ?? enterononulo);//Válido entre tipos anulables.
//z=123

 Console.WriteLine(s ?? "s nula");// Escribe s nula.

    Lo que obviamente no se permite es aplicarlo entre tipos no anulables puesto que no tiene sentido en tanto que nunca será posible que alguno de sus operandos valga null. Tampoco es aplicable entre tipos referencia y tipos valor ya que el resultado de la expresión podría ser de tipo valor o de tipo referencia dependiendo de los operandos que en concreto se les pase en cada ejecución de la misma, y por tanto no podría almacenarse con seguridad en ningún tipo de variable salvo object. Por tanto, todas las siguientes asignaciones son incorrectas (excepto las de las inicializaciones, claro):


 int x = 1;
 int? y = 1;
 int z = 0;
 string s = null;
 z = 1 ?? 1;   // No válido entre tipos valor
 z = x ?? 123; // De nuevo, no válido entre tipos valor
 z = s ?? x;   // No válido entre tipos referencia y tipos valor.
 z = s ?? y;   // Ni aunque el tipo valor sea anulable.

    El operador ?? es asociativo por la derecha, por lo que puede combinarse como sigue:


 using System;
 class OperadorFusión
 {
  static void Main()
  {
   string s = null, t = null;
   Console.WriteLine(s ?? t ?? "s y t son cadenas nulas");
   t = "Ahora t no es nula";
   Console.WriteLine(s ?? t ?? "s y t son cadenas nulas");
   s = "Ahora s no es nula";
   Console.WriteLine(s ?? t ?? "s y t son cadenas nulas");
  }
 }

    Siendo el resultado de la ejecución del código el siguiente:

s y t son cadenas nulas

Ahora t no es nula

Ahora s no es nula


Inicio | Tutorial C# Mejoras en la manipulación de delegadosTutorial C#Modificadores de visibilidad de bloques get y set Versión para imprimir Foros de consulta


Añadir comentario ... Para preguntar utiliza los foros
Autor:

Título:


Para preguntar utiliza los foros.



Inicio | Tutorial C# Mejoras en la manipulación de delegadosTutorial C#Modificadores de visibilidad de bloques get y set Versión para imprimir

Tipos anulables
Autor: José Antonio González Seco
Visitas: 4521 Fecha de publicación: 03/01/2007
José Antonio es experto en tecnologias Microsoft. Imparte cursos y conferencias en congresos sobre C# y .NET en Universidades de toda España (Sevilla, Barcelona, San Sebastián, Valencia, Oviedo, etc.) en representación de grandes empresas como Microsoft.




Visitas: 310 | Comentarios: 0 | Archivo: Articulos
Categorias: Visual Basic .NET|C#|ASP.NET|ASP.NET|Programación|ADO.NET
27/09/2008 Navegando ....
Visitas: 85 | Comentarios: 0 | Archivo: Articulos
Categorias: Humor
Visitas: 207 | Comentarios: 0 | Archivo: Articulos
Categorias: Visual Basic .NET|C#|ASP.NET|ASP.NET|Programación|WCF
Visitas: 937 | Comentarios: 0 | Archivo: Articulos
Categorias: C#
Visitas: 209 | Comentarios: 0 | Archivo: Articulos
Categorias: JavaScript|ASP.NET
Visitas: 675 | Comentarios: 0 | Archivo: Articulos
Categorias: Windows XP|Linux|Windows Vista
Visitas: 455 | Comentarios: 0 | Archivo: Articulos
Categorias: Linux|BSD
Visitas: 236 | Comentarios: 0 | Archivo: Articulos
Categorias: Programación|Actualidad
18/08/2008 SQL Server 2008
Visitas: 1135 | Comentarios: 1 | Archivo: Articulos
Categorias: Transact-SQL
Visitas: 789 | Comentarios: 0 | Archivo: Articulos
Categorias: C#|ADO.NET|LinQ

Útimos temas recibidos en los foros ...
Coastal Inversiones SAC Coastal Vacations Oportunidad de Negocios por lecasur ... [ASP.NET] 0 11/10/2008
Negocios Rentables desde tu Hogar Coastal Vacations por lecasur ... [Access] 0 11/10/2008
COASTAL VACATIONS OPORTUNIDAD DE NEGOCIOS RENTABLES por lecasur ... [Actualidad] 0 11/10/2008
hacer el nombre de una tabla variable por leicolei ... [SQL Server] 2 10/10/2008
ayuda por yo ... [C#] 2 09/10/2008
Mostar nombre en una sesion de usuario por jhors ... [ASP.NET] 1 10/10/2008
Analista por Rolando ... [SQL Server] 0 10/10/2008
SQL dinámico en TRIGGERS por Alastor ... [ORACLE] 2 03/10/2008
Crystal Reports 8.5 por selvinalberto ... [Visual Basic 6.0] 0 10/10/2008
Agregar Columnas a un datagridview por Tony ... [Visual Basic .NET] 3 20/11/2007
Problema cargando un pl/sql Embebido en Pro*C por ejrivas ... [ORACLE] 0 10/10/2008
Verificar conexion a internet por giraldo ... [Visual Basic .NET] 3 11/12/2006

Access CGI JSP ORACLE UNIX
Actualidad HTML/DHTML/XHTML LINUX PHP Visual Basic .NET
ASP ISAPI MS DOS Power Builder Visual Basic 6.0
ASP.NET Java mySQL SQL WIN 98/NT/2000/XP
C# JavaScript Opinion SQL Server

devjoker  Te recomendamos además ...
30/05/2006 Poner un fondo en la Barra de herramientas de Mi PC y el Explorador de Windows
18/10/2005 Enviar emails a través de un servidor SMTP autenticado con Java
31/03/2006 Fundamentos de PL/SQL    forma parte de...Tutorial PL/SQL
28/08/2006 Ubuntu en VmWare con VMware Tools
01/01/2006 Borrado de datos. DELETE    forma parte de...Tutorial SQL
03/10/2006 Introduccion a C#    forma parte de...Tutorial C#
27/08/2007 Enviar email con C#
01/06/2007 Autogenerado ESSALUD (Solución)
22/10/2005 Actualización de datos. UPDATE    forma parte de...Tutorial SQL
23/05/2006 Cursores en PL/SQL    forma parte de...Tutorial PL/SQL

 

Encuesta
¿A que perfil te adaptas mejor?
[Ver] [Votar]