Módulo 02: Tipos de datos

Objetivos del módulo

  • Entender qué son las variables y por qué son necesarias
  • Conocer todos los tipos de datos básicos de C#
  • Aprender a declarar e inicializar variables
  • Comprender las conversiones entre tipos
  • Usar var, constantes y tipos nulables
  • Leer datos del usuario con Console.ReadLine()

1. ¿Qué es una variable?

📘 Concepto: Una variable es como una “caja” con un nombre donde guardas un valor. Puedes poner cosas dentro, sacarlas, cambiarlas, etc. Cada caja tiene una etiqueta (el nombre) y solo puede guardar un tipo específico de dato.

┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│  edad        │    │  nombre      │    │  precio      │
│  ┌────────┐  │    │  ┌────────┐  │    │  ┌────────┐  │
│  │   25   │  │    │  │ "Ana"  │  │    │  │  9.99  │  │
│  └────────┘  │    │  └────────┘  │    │  └────────┘  │
│  (int)       │    │  (string)    │    │  (double)    │
└──────────────┘    └──────────────┘    └──────────────┘

Para crear una variable en C# necesitas tres cosas:

  1. El tipo: qué tipo de dato va a guardar (número entero, texto, decimal…)
  2. El nombre: cómo se llama la variable (para poder usarla después)
  3. El valor (opcional): qué valor tiene inicialmente
// Sintaxis: tipo nombre = valor;
int edad = 25;
string nombre = "Ana";
double precio = 9.99;

2. Tipos de datos numéricos enteros

Los tipos enteros almacenan números sin decimales.

Tipos enteros disponibles

Tipo Tamaño Rango Uso habitual
byte 1 byte 0 a 255 Valores pequeños positivos
sbyte 1 byte -128 a 127 Valores pequeños con signo
short 2 bytes -32.768 a 32.767 Números medianos
ushort 2 bytes 0 a 65.535 Números medianos positivos
int 4 bytes -2.147.483.648 a 2.147.483.647 El más usado
uint 4 bytes 0 a 4.294.967.295 Números grandes positivos
long 8 bytes ±9,2 × 10¹⁸ Números muy grandes
ulong 8 bytes 0 a 1,8 × 10¹⁹ Números enormes positivos

💡 Consejo: En la práctica, el 99% de las veces usarás int. Solo necesitarás long para números muy grandes (como el número de habitantes del mundo) y byte para trabajo con datos binarios.

Ejemplo completo

// Declarar variables enteras
int edad = 30;
int temperatura = -5;         // Los int pueden ser negativos
int poblacionCiudad = 3500000;

long poblacionMundial = 8000000000L;  // La "L" indica que es long
byte nivelBateria = 85;               // 0 a 255, perfecto para porcentajes

// Mostrar los valores
Console.WriteLine("Edad: " + edad);
Console.WriteLine("Temperatura: " + temperatura + "°C");
Console.WriteLine("Población de la ciudad: " + poblacionCiudad);
Console.WriteLine("Población mundial: " + poblacionMundial);
Console.WriteLine("Nivel de batería: " + nivelBateria + "%");

Explicación línea por línea:

Línea Código Explicación
int edad = 30; Crea una variable llamada edad de tipo int (número entero) y le asigna el valor 30  
int temperatura = -5; Los números enteros con signo (int) pueden almacenar valores negativos  
long poblacionMundial = 8000000000L; Usamos long porque 8.000 millones supera el límite de int. La L al final indica que el literal es de tipo long  
"Edad: " + edad El operador + con strings concatena (une) el texto con el valor de la variable  

Salida:

Edad: 30
Temperatura: -5°C
Población de la ciudad: 3500000
Nivel de batería: 85%
Población mundial: 8000000000

Separadores numéricos

Para mejorar la legibilidad de números grandes, puedes usar el guion bajo _ como separador visual:

int millon = 1_000_000;           // Más fácil de leer que 1000000
long billonEuropeo = 1_000_000_000_000L;
int binario = 0b_1010_1100;       // Número en binario
int hexadecimal = 0xFF_AA_00;     // Número en hexadecimal

📘 Concepto: Los guiones bajos son ignorados por el compilador, solo sirven para que los humanos leamos los números más fácilmente. 1_000_000 y 1000000 son exactamente lo mismo.


3. Tipos de datos numéricos decimales

Los tipos decimales almacenan números con parte fraccionaria.

Tipo Tamaño Precisión Rango aproximado Uso habitual
float 4 bytes ~6-7 dígitos ±3,4 × 10³⁸ Gráficos, juegos
double 8 bytes ~15-16 dígitos ±1,7 × 10³⁰⁸ El más usado para decimales
decimal 16 bytes 28-29 dígitos ±7,9 × 10²⁸ Dinero y finanzas

Ejemplo completo

// double: el tipo decimal más común
double pi = 3.141592653589793;
double altura = 1.75;
double temperaturaExacta = -12.5;

// float: menos precisión, necesita la "f" al final
float velocidad = 120.5f;
float nota = 7.8f;

// decimal: alta precisión para dinero (necesita la "m" al final)
decimal precio = 29.99m;
decimal salario = 2500.50m;
decimal impuesto = 0.21m;

// Cálculo con dinero
decimal total = precio * (1 + impuesto);

Console.WriteLine($"Pi: {pi}");
Console.WriteLine($"Altura: {altura} metros");
Console.WriteLine($"Velocidad: {velocidad} km/h");
Console.WriteLine($"Precio: {precio}€");
Console.WriteLine($"Salario: {salario}€");
Console.WriteLine($"Total con IVA (21%): {total:F2}€");

Explicación línea por línea:

Línea Código Explicación
double pi = 3.14159...; double es el tipo decimal por defecto. No necesita sufijo.  
float velocidad = 120.5f; float necesita la letra f al final para distinguirlo de double.  
decimal precio = 29.99m; decimal necesita la letra m al final. Usar siempre para dinero.  
$"Pi: {pi}" Esto es interpolación de cadenas: el $ permite insertar variables dentro del texto usando {variable}.  
{total:F2} El formato F2 muestra el número con exactamente 2 decimales.  

⚠️ Importante: ¿Por qué usar decimal para dinero y no double? Porque double tiene errores de precisión con decimales. Por ejemplo, 0.1 + 0.2 en double da 0.30000000000000004, ¡no 0.3! Con decimal esto no ocurre.

// Demostración del problema de precisión con double
double resultadoDouble = 0.1 + 0.2;
decimal resultadoDecimal = 0.1m + 0.2m;

Console.WriteLine($"double: 0.1 + 0.2 = {resultadoDouble}");   // 0.30000000000000004
Console.WriteLine($"decimal: 0.1 + 0.2 = {resultadoDecimal}"); // 0.3

4. Tipo booleano (bool)

El tipo bool solo puede tener dos valores: true (verdadero) o false (falso).

bool esMayorDeEdad = true;
bool estaLloviendo = false;
bool tienePermiso = true;

Console.WriteLine($"¿Es mayor de edad? {esMayorDeEdad}");   // True
Console.WriteLine($"¿Está lloviendo? {estaLloviendo}");     // False

// Los bool se generan frecuentemente con comparaciones
int edad = 25;
bool puedeVotar = edad >= 18;  // true, porque 25 >= 18
Console.WriteLine($"¿Puede votar? {puedeVotar}");           // True

📘 Concepto: Los booleanos son fundamentales en programación. Se usan en todas las decisiones del programa: “si esto es verdadero, haz una cosa; si es falso, haz otra”. Los veremos mucho en el módulo de estructuras de control.


5. Tipo carácter (char)

El tipo char almacena un único carácter Unicode. Se escribe entre comillas simples ' '.

char letra = 'A';
char numero = '7';          // Es el carácter '7', no el número 7
char simbolo = '@';
char emoji = '♥';
char letraEspanola = 'ñ';

Console.WriteLine($"Letra: {letra}");
Console.WriteLine($"Símbolo: {simbolo}");
Console.WriteLine($"Emoji: {emoji}");
Console.WriteLine($"Valor numérico de 'A': {(int)letra}");  // 65 (código ASCII/Unicode)

⚠️ Importante: No confundas char (un carácter, comillas simples 'A') con string (texto, comillas dobles "Hola"). 'A' es un char, "A" es un string.


6. Tipo cadena de texto (string)

El tipo string almacena una secuencia de caracteres (texto). Se escribe entre comillas dobles " ".

string nombre = "María";
string apellido = "García";
string frase = "¡Hola, mundo!";
string vacio = "";              // String vacío (sin caracteres)

// Concatenación (unir strings)
string nombreCompleto = nombre + " " + apellido;
Console.WriteLine(nombreCompleto);  // María García

// Interpolación de cadenas (forma moderna y recomendada)
string saludo = $"Hola, {nombre} {apellido}. ¡Bienvenida!";
Console.WriteLine(saludo);  // Hola, María García. ¡Bienvenida!

// Longitud del string
Console.WriteLine($"Tu nombre tiene {nombre.Length} letras");  // 5

Cadenas multilínea (raw string literals)

C# permite escribir cadenas que ocupan varias líneas de forma muy legible (disponible desde C# 11):

// Cadenas multilínea con """ (triple comilla)
string menu = """
    ╔══════════════════════════╗
        MENÚ PRINCIPAL        
    ╠══════════════════════════╣
      1. Nuevo juego          
      2. Cargar partida       
      3. Opciones             
      4. Salir                
    ╚══════════════════════════╝
    """;
Console.WriteLine(menu);

Secuencias de escape

Algunos caracteres especiales se escriben con una barra invertida \:

Secuencia Significado Ejemplo
\n Salto de línea "Línea 1\nLínea 2"
\t Tabulación "Nombre:\tAna"
\\ Barra invertida literal "C:\\Users\\Ana"
\" Comilla doble literal "Dijo \"hola\""
// Secuencias de escape
Console.WriteLine("Primera línea\nSegunda línea");
Console.WriteLine("Nombre:\tAna");
Console.WriteLine("Ruta: C:\\Users\\Ana\\Documentos");

// Alternativa: cadena verbatim con @
string ruta = @"C:\Users\Ana\Documentos";  // No necesita \\
Console.WriteLine(ruta);

7. La palabra clave var

var permite que el compilador deduzca automáticamente el tipo de la variable a partir del valor que le asignas.

var edad = 25;              // El compilador deduce que es int
var nombre = "Ana";         // El compilador deduce que es string
var precio = 9.99;          // El compilador deduce que es double
var activo = true;          // El compilador deduce que es bool

// Es exactamente equivalente a:
int edad2 = 25;
string nombre2 = "Ana";
double precio2 = 9.99;
bool activo2 = true;

⚠️ Importante: var no significa que la variable no tiene tipo. El tipo se define en el momento de la compilación y no puede cambiar después. var simplemente ahorra escritura.

var numero = 10;     // Es int
// numero = "hola";  // ❌ ERROR: no puedes asignar un string a una variable int
numero = 20;         // ✅ Correcto: puedes asignar otro int

💡 Consejo: Usa var cuando el tipo sea obvio por el contexto. Usa el tipo explícito cuando quieras dejar claro qué tipo es.


8. Constantes

Una constante es una variable cuyo valor nunca cambia durante la ejecución del programa.

const double PI = 3.141592653589793;
const int DIAS_SEMANA = 7;
const string MONEDA = "EUR";
const int MAYORIA_EDAD = 18;

Console.WriteLine($"Pi vale: {PI}");
Console.WriteLine($"Una semana tiene {DIAS_SEMANA} días");

// PI = 3.14;  // ❌ ERROR: no se puede modificar una constante

💡 Consejo: Por convención, las constantes se escriben en MAYÚSCULAS_CON_GUIONES_BAJOS o en PascalCase. Usa constantes para valores que nunca cambian: el número de días de la semana, el IVA, etc.


9. Leer datos del usuario

Para leer lo que el usuario escribe en la consola, usamos Console.ReadLine().

// Pedir el nombre
Console.Write("¿Cómo te llamas? ");
string nombre = Console.ReadLine();

// Pedir la edad (ReadLine devuelve string, hay que convertir a int)
Console.Write("¿Cuántos años tienes? ");
string edadTexto = Console.ReadLine();
int edad = int.Parse(edadTexto);

// Pedir la altura
Console.Write("¿Cuánto mides (en metros)? ");
string alturaTexto = Console.ReadLine();
double altura = double.Parse(alturaTexto);

// Mostrar los datos
Console.WriteLine();
Console.WriteLine("═══════════════════════════");
Console.WriteLine($"  Nombre: {nombre}");
Console.WriteLine($"  Edad: {edad} años");
Console.WriteLine($"  Altura: {altura} m");
Console.WriteLine("═══════════════════════════");

Explicación línea por línea:

Línea Código Explicación
Console.Write("¿Cómo te llamas? ") Muestra el texto sin saltar de línea (para que el cursor quede al lado)  
Console.ReadLine() Espera a que el usuario escriba algo y pulse Enter. Devuelve lo que ha escrito como string  
int.Parse(edadTexto) Convierte el texto "25" al número 25. Si el usuario escribe algo que no es un número, dará error  
double.Parse(alturaTexto) Convierte el texto "1.75" al número decimal 1.75  

⚠️ Importante: Console.ReadLine() siempre devuelve un string. Si necesitas un número, debes convertirlo con int.Parse(), double.Parse(), etc.


10. Conversiones de tipos

Conversiones implícitas (automáticas)

C# convierte automáticamente cuando no hay riesgo de perder datos (de tipo “pequeño” a tipo “grande”):

int entero = 42;
long grande = entero;       // ✅ int → long (automático, sin perder datos)
double decimal1 = entero;   // ✅ int → double (automático)

float flotante = 3.14f;
double decimal2 = flotante; // ✅ float → double (automático)

Console.WriteLine($"entero: {entero}");        // 42
Console.WriteLine($"grande (long): {grande}"); // 42
Console.WriteLine($"decimal: {decimal1}");     // 42
Conversiones implícitas (automáticas):
byte → short → int → long → float → double
                              ↓
                           decimal (solo desde enteros)

Conversiones explícitas (casting)

Cuando hay riesgo de perder datos, debes hacer un cast explícito:

double precio = 9.99;
int precioRedondeado = (int)precio;  // Casting: se pierden los decimales
Console.WriteLine(precioRedondeado); // 9 (NO redondea, TRUNCA)

long numeroGrande = 1000;
int numeroNormal = (int)numeroGrande;  // Casting de long a int

// Cuidado con el desbordamiento:
int valor = 300;
byte valorByte = (byte)valor;  // ⚠️ 300 no cabe en byte (0-255)
Console.WriteLine(valorByte);  // 44 (resultado inesperado por desbordamiento)

⚠️ Importante: El casting con (tipo) no redondea, sino que trunca (corta los decimales). Para redondear, usa Math.Round():

double precio = 9.99;
int truncado = (int)precio;                      // 9  (trunca)
int redondeado = (int)Math.Round(precio);        // 10 (redondea)
Console.WriteLine($"Truncado: {truncado}");      // 9
Console.WriteLine($"Redondeado: {redondeado}");  // 10

Conversiones con Parse y Convert

// string → número con Parse
string textoEdad = "25";
int edad = int.Parse(textoEdad);           // 25
double altura = double.Parse("1.75");      // 1.75

// string → número con Convert
int edad2 = Convert.ToInt32("25");         // 25
double altura2 = Convert.ToDouble("1.75"); // 1.75
bool activo = Convert.ToBoolean("true");   // true

// número → string
int numero = 42;
string texto = numero.ToString();          // "42"
string texto2 = $"{numero}";              // "42" (con interpolación)

Conversión segura con TryParse

Parse lanza una excepción si el texto no es un número válido. TryParse es más seguro:

Console.Write("Introduce un número: ");
string entrada = Console.ReadLine();

// TryParse devuelve true si la conversión fue exitosa
if (int.TryParse(entrada, out int numero))
{
    Console.WriteLine($"Has introducido el número: {numero}");
}
else
{
    Console.WriteLine("Eso no es un número válido.");
}

Explicación:

Parte Explicación
int.TryParse(entrada, out int numero) Intenta convertir entrada a int. Si tiene éxito, guarda el resultado en numero y devuelve true. Si falla, devuelve false.
out int numero La palabra out indica que TryParse va a “llenar” esta variable con el resultado.

11. Tipos nulables (Nullable)

Por defecto, los tipos de valor (int, double, bool, etc.) no pueden ser null (sin valor). Pero a veces necesitas representar “no hay valor”. Para eso existen los tipos nulables:

int? edadDesconocida = null;   // El ? permite que sea null
double? peso = null;
bool? respuesta = null;        // No ha respondido

// Asignar un valor después
edadDesconocida = 25;

// Comprobar si tiene valor
if (edadDesconocida.HasValue)
{
    Console.WriteLine($"Edad: {edadDesconocida.Value}");
}
else
{
    Console.WriteLine("Edad desconocida");
}

// Operador ?? (null-coalescing): valor por defecto si es null
int edadFinal = edadDesconocida ?? 0;  // Si es null, usa 0
Console.WriteLine($"Edad final: {edadFinal}");

📘 Concepto: Los strings ya pueden ser null por defecto (son tipos de referencia). Pero con <Nullable>enable</Nullable> en el .csproj, el compilador te avisa si un string podría ser null y no lo estás manejando.


12. Tabla resumen de tipos

Tipo Categoría Tamaño Ejemplo Uso principal
int Entero 4 bytes 42 Números enteros (el más común)
long Entero 8 bytes 8000000000L Números muy grandes
byte Entero 1 byte 255 Datos binarios, porcentajes
double Decimal 8 bytes 3.14 Decimales (el más común)
float Decimal 4 bytes 3.14f Gráficos, juegos
decimal Decimal 16 bytes 29.99m Dinero y finanzas
bool Booleano 1 byte true / false Condiciones lógicas
char Carácter 2 bytes 'A' Un solo carácter
string Texto Variable "Hola" Cadenas de texto

13. Ejercicios

Ejercicio 1: Ficha personal

Crea un programa que pida al usuario su nombre, edad, altura y ciudad, y muestre una ficha personal formateada:

Introduce tu nombre: Ana
Introduce tu edad: 25
Introduce tu altura (m): 1.68
Introduce tu ciudad: Madrid

══════════════════════════════
  FICHA PERSONAL
══════════════════════════════
  Nombre:  Ana
  Edad:    25 años
  Altura:  1.68 m
  Ciudad:  Madrid
══════════════════════════════

Ejercicio 2: Calculadora de propinas

Crea un programa que pida el importe de una comida y el porcentaje de propina, y calcule el total:

Importe de la comida: 45.50
Porcentaje de propina (%): 15

  Importe:  45.50€
  Propina (15%):  6.83€
  TOTAL:  52.33€

Pista: Usa decimal para los importes monetarios.

Ejercicio 3: Conversor de temperaturas

Crea un programa que convierta grados Celsius a Fahrenheit y viceversa:

  • Fórmula: °F = °C × 9/5 + 32
  • Fórmula inversa: °C = (°F - 32) × 5/9

Ejercicio 4: Intercambiar variables

Declara dos variables int a = 10 y int b = 20. Intercambia sus valores sin usar una tercera variable (investiga cómo hacerlo con tuplas):

int a = 10;
int b = 20;
// Tu código aquí para intercambiar
// Resultado: a = 20, b = 10

Solución con tuplas:

int a = 10;
int b = 20;
(a, b) = (b, a);  // ¡Intercambio con tuplas en una línea!
Console.WriteLine($"a = {a}, b = {b}");  // a = 20, b = 10

Ejercicio 5: Validación con TryParse

Mejora el ejercicio de la ficha personal para que si el usuario introduce una edad o altura inválida (texto en vez de número), muestre un mensaje de error en vez de fallar.


Resumen

Concepto Detalle
Variable “Caja” con nombre que almacena un valor de un tipo específico
int Número entero (el más usado)
double Número decimal (el más usado)
decimal Número decimal de alta precisión (para dinero)
bool Verdadero (true) o falso (false)
char Un solo carácter ('A')
string Cadena de texto ("Hola")
var Deducción automática de tipo
const Constante: valor que no cambia
int? Tipo nulable: puede ser null
Console.ReadLine() Leer texto del usuario
int.Parse() Convertir string a int
int.TryParse() Conversión segura (no lanza excepción)
Interpolación $"Hola, {nombre}" para insertar variables en texto