3 TIPOS DE DATOS

C# es un lenguaje con establecimiento inflexible de tipos; por lo tanto, cada variable y objeto debe tener un tipo declarado.

Información general sobre los tipos de datos

Un tipo de datos se puede describir como:

  • Un tipo de datos integrado, como int o char, o bien
  • Un tipo de datos definidos por el usuario, como class o interface.
  • Los tipos de datos también se pueden definir como:
  • Tipos de valores (Referencia de C#), que almacenan los valores, o bien
  • Tipos de referencia (Referencia de C#), que almacenan referencias a los datos reales.

Secciones relacionadas

Para obtener más información:

  • Conversión (Guía de programación de C#)
  • Conversión boxing y unboxing (Guía de programación de C#)
  • Tipos (Referencia de C#)
  • Objetos, clases y estructuras (Guía de programación de C#)

3.1.- TIPOS DE VALORES

Los tipos de valor consisten en dos categorías principales:

  • Estructuras
  • Enumeraciones

Las estructuras se dividen en las siguientes categorías:

  • Tipos numéricos
    • Tipos integrales
    • Tipos de punto flotante
    • decimal
  • Estructuras definidas por el usuario.

Características principales de los tipos de valor

Variable que está basada directamente en tipos de valor que contienen valores. La asignación de una variable de tipo de valor a otra copia el valor contenido. Esto es diferente de la asignación de variables de tipo de referencia, que copia una referencia en el objeto pero no el propio objeto.

Todos los tipos de valor se derivan implícitamente de la clase System.ValueType.

A diferencia de los tipos de referencia, no es posible obtener un nuevo tipo de un tipo de valor. No obstante, al igual que los tipos de referencia, las estructuras pueden implementar interfaces.

A diferencia de los tipos de referencia, los tipos de valor no pueden incluir el valor null. Sin embargo, la característica tipos que aceptan valores NULL permite asignar null a tipos de valores.

Cada tipo de valor tiene un constructor implícito predeterminado que inicializa el valor predeterminado de ese tipo. Para obtener información sobre los valores predeterminados de los tipos de valor, vea Tabla de valores predeterminados.

Características principales de los tipos simples

Todos los tipos simples (aquellos que forman parte integral del lenguaje C#) son alias de los tipos del sistema .NET Framework. Por ejemplo, int es un alias de System.Int32. Para una lista completa de alias, vea Tabla de tipos integrados (Referencia de C#).

Las expresiones constantes, cuyos operandos son todos constantes de tipos simples, se evalúan en tiempo de compilación.

Los tipos simples se pueden inicializar mediante literales. Por ejemplo, ‘A’ es un literal del tipo char y 2001 es un literal del tipo int.

Inicializar tipos de valor

Las variables locales de C# se deben inicializar antes de utilizarlas. Por consiguiente, si se declara una variable local sin inicialización como ésta:

int myInt;        

no se podrá utilizar hasta que se inicialice. La inicialización se puede realizar mediante la siguiente instrucción:

myInt = new int(); // Invoke default constructor for int type.

que equivale a:

myInt = 0; // Assign an initial value, 0 in this example.

También se puede realizar la declaración y la inicialización en la misma instrucción:

int myInt = new int();

O bien

int myInt = 0;

Con el operador new, se realiza una llamada al constructor predeterminado del tipo específico y se asigna el valor predeterminado a la variable. En el ejemplo anterior, el constructor predeterminado asigna a myInt el valor 0. Para obtener más información sobre valores asignados mediante constructores predeterminados, vea Tabla de valores predeterminados.

Con los tipos definidos por el usuario, se utiliza new para invocar el constructor predeterminado. Por ejemplo, la siguiente instrucción invoca el constructor predeterminado de la estructura Point:

Point p = new Point(); // Invoke default constructor for the struct.

Después de esta llamada, la estructura se considera definitivamente asignada; es decir, todos sus miembros se inicializan con sus valores predeterminados.

Para obtener más información acerca del operador new.

3.1.1.- ESTRUCTURAS

Un tipo struct es un tipo de valor que se suele utilizar para encapsular pequeños grupos de variables relacionadas, como las coordenadas de un rectángulo o las características de un elemento de un inventario. En el ejemplo siguiente se muestra una declaración de estructura sencilla.


 

Comentarios

Las estructuras también pueden contener constructores, constantes, campos, métodos, propiedades, indizadores, operadores, eventos y tipos anidados, aunque si se requieren estos miembros, se debe considerar la posibilidad de crear una clase en vez de un tipo.

Las estructuras pueden implementar una interfaz, pero no pueden heredar de otra estructura. Por esa razón, los miembros de estructura no se pueden declarar como protected.

3.1.2.- ENUMERACIONES

La palabra clave enum se utiliza para declarar una enumeración, un tipo distinto que consiste en un conjunto de constantes con nombre denominado lista de enumeradores. Cada tipo de enumeración tiene un tipo subyacente, que puede ser cualquier tipo integral excepto char. El tipo predeterminado subyacente de los elementos de la enumeración es int. De forma predeterminada, el primer enumerador tiene el valor 0 y el valor de cada enumerador sucesivo se incrementa en 1. Por ejemplo:


enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri};

En esta enumeración, Sat es 0, Sun es 1, Mon es 2 y así sucesivamente. Los enumeradores pueden tener inicializadores que reemplazan a los valores predeterminados. Por ejemplo:


enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};

En esta enumeración, se obliga a que la secuencia de elementos empiece en 1 en vez de en 0.

A una variable de tipo Days se le puede asignar cualquier valor en el intervalo del tipo subyacente; los valores no se limitan a las constantes con nombre.

El valor predeterminado de un enum E es el valor producido por la expresión (E)0.

Nota

Un enumerador no puede contener espacio en blanco en su nombre.

El tipo subyacente especifica el almacenamiento asignado para cada enumerador. No obstante, se necesita una conversión explícita para convertir un tipo enum a un tipo integral. Por ejemplo, la siguiente instrucción asigna el enumerador Sun a una variable de tipo int utilizando una conversión explícita para convertir de enum a int:

int x = (int)Days.Sun;

Cuando se aplica System.FlagsAttribute a una enumeración que contiene algunos elementos combinados con una operación OR bit a bit, se observará que el atributo afecta el comportamiento de enum cuando se utiliza con algunas herramientas. Se pueden observar estos cambios al utilizar herramientas tales como los métodos de la clase Console, el Evaluador de expresiones, etc. (Vea el ejemplo 3).

Programación sólida

Asignar valores adicionales a nuevas versiones de enumeraciones o cambiar los valores de los miembros de enumeración en una nueva versión, puede producir problemas para el código fuente dependiente. Es común que los valores enum se utilicen en instrucciones switch y, si se han agregado elementos adicionales al tipo enum, la comprobación de los valores predeterminados puede devolver true de forma inesperada.

Si otros desarrolladores van a utilizar su código, es importante proporcionar instrucciones sobre cómo su código debe reaccionar si se agregan nuevos elementos a cualquier tipo enum.

Ejemplo

En este ejemplo, se declara la enumeración Days. Dos enumeradores se convierten explícitamente en un número entero y se asignan a variables de número entero.

// keyword_enum.cs

// enum initialization:

using System;

public class EnumTest

{

enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};

static void Main()

{


int x = (int)Days.Sun;


int y = (int)Days.Fri;

Console.WriteLine(«Sun = {0}», x);

Console.WriteLine(«Fri = {0}», y);

}

}

Resultados

Sun = 2

Fri = 7

En este ejemplo, la opción de tipo base se utiliza para declarar un enum cuyos miembros son del tipo long. Observe que a pesar de que el tipo subyacente de la enumeración es long, los miembros de la enumeración todavía deben convertirse explícitamente al tipo long mediante una conversión de tipos.

// keyword_enum2.cs

// Using long enumerators

using System;

public class EnumTest

{

enum Range :long {Max = 2147483648L, Min = 255L};

static void Main()

{


long x = (long)Range.Max;


long y = (long)Range.Min;

Console.WriteLine(«Max = {0}», x);

Console.WriteLine(«Min = {0}», y);

}

}

Resultados

Max = 2147483648

Min = 255

El ejemplo de código siguiente ilustra el uso y efecto del atributo System.FlagsAttribute en una declaración enum.

// enumFlags.cs

// Using the FlagsAttribute on enumerations.

using System;

[Flags]

public enum CarOptions

{

SunRoof = 0x01,

Spoiler = 0x02,

FogLights = 0x04,

TintedWindows = 0x08,

}

class FlagTest

{

static void Main()

{

CarOptions options = CarOptions.SunRoof | CarOptions.FogLights;

Console.WriteLine(options);

Console.WriteLine((int)options);

}

}

Resultados

SunRoof, FogLights

5

Comentarios

Observe que si se quita el inicializador de Sat=1, el resultado será:

Sun = 1

Fri = 6

Comentarios

Observe que si elimina FlagsAttribute, el ejemplo generará lo siguiente:

5

5

3.2.- TIPOS DE REFERENCIA

Las variables de tipos de referencia, conocidas como objetos, almacenan referencias a los datos reales. Esta sección presenta las palabras clave siguientes utilizadas para declarar tipos de referencia:

Esta sección también presenta los siguientes tipos de referencia integrados:

3.3.- CONVERSIONES DE TIPOS DE DATOS

La conversión entre tipos de datos se puede hacer de forma explícita utilizando una conversión de tipos; en algunos casos, se permiten conversiones implícitas. Por ejemplo:

static void TestCasting()

{

int i = 10;

float f = 0;

f = i; // An implicit conversion, no data will be lost.

f = 0.5F;

i = (int) f; // An explicit conversion. Information will be lost.

}

Una conversión de tipos invoca de forma explícita al operador de conversión de un tipo a otro. En la conversión de tipos se producirá un error si no se ha definido ninguno de estos operadores. Puede escribir operadores de conversión personalizados para convertir entre los tipos definidos por el usuario. Para obtener más información sobre la definición de un operador de conversión, vea explicit (Referencia de C#) e implicit (Referencia de C#).

Ejemplo

El siguiente programa convierte explícitamente un tipo double en un tipo int. El programa no se compilará sin el operador de conversión de tipo.

class Test

{

static void Main()

{

double x = 1234.7;

int a;

a = (int)x; // cast double to int

System.Console.WriteLine(a);

}

}

Resultado

1234

3.4.- CONVERSION. BOXING Y UNBOXING

Las conversiones boxing y unboxing permiten tratar los tipos de valor como objetos. La aplicación de la conversión boxing a un tipo de valor empaqueta el tipo en una instancia del tipo de referencia Object. Esto permite almacenar el tipo de valor en el montón del recolector de elementos no utilizados. La conversión unboxing extrae el tipo de valor del objeto. En este ejemplo, se aplica la conversión boxing a la variable de entero i y ésta se asigna al objeto o.

int i = 123;

object o = (object) i; // boxing

A continuación, se puede aplicar la conversión unboxing al objeto o y asignarlo a la variable de entero i:

o = 123;

i = (int) o; // unboxing

Rendimiento

Con relación a las asignaciones simples, las conversiones boxing y unboxing son procesos que consumen muchos recursos. Cuando se aplica la conversión boxing a un tipo de valor, se debe asignar y construir un objeto completamente nuevo. En menor grado, la conversión de tipos requerida para aplicar la conversión unboxing también es costosa.