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:
- El tipo: qué tipo de dato va a guardar (número entero, texto, decimal…)
- El nombre: cómo se llama la variable (para poder usarla después)
- 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áslongpara números muy grandes (como el número de habitantes del mundo) ybytepara 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_000y1000000son 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
decimalpara dinero y nodouble? Porquedoubletiene errores de precisión con decimales. Por ejemplo,0.1 + 0.2endoubleda0.30000000000000004, ¡no0.3! Condecimalesto 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') constring(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:
varno significa que la variable no tiene tipo. El tipo se define en el momento de la compilación y no puede cambiar después.varsimplemente 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
varcuando 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 unstring. Si necesitas un número, debes convertirlo conint.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, usaMath.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
nullpor defecto (son tipos de referencia). Pero con<Nullable>enable</Nullable>en el.csproj, el compilador te avisa si un string podría sernully 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 |