Toda aplicación necesita almacenar y manipular datos: el título de un libro, la cantidad de páginas, si un ejemplar está disponible o no. En C#, esos datos se guardan en variables, y cada variable tiene un tipo que determina qué clase de valores puede contener y qué operaciones se pueden hacer con ellos. En esta lección aprenderás a declarar variables, a distinguir entre los tipos de valor y los tipos de referencia, a convertir datos de un tipo a otro, a definir constantes, y a entender el ámbito (scope) de una variable. Usaremos siempre datos del catálogo de BiblioTech —título, ISBN, número de páginas, disponibilidad— como hilo conductor de todos los ejemplos.

Contenido

  1. Declaración de variables: tipos explícitos y var
  2. Tipos de valor
  3. Tipos de referencia
  4. Conversión de tipos
  5. Constantes: const y readonly
  6. Ámbito de las variables
  7. Valores por defecto y nulabilidad básica

Declaración de variables: tipos explícitos y var

Declarar una variable en C# significa indicarle al compilador tres cosas: su tipo, su nombre, y (opcionalmente, pero recomendable) un valor inicial. La sintaxis general es:

tipo nombreVariable = valorInicial;

Por ejemplo, para representar el título de un libro de BiblioTech:

string tituloLibro = "Cien anos de soledad";
int numeroPaginas = 471;
bool estaDisponible = true;

Console.WriteLine(tituloLibro);
Console.WriteLine(numeroPaginas);
Console.WriteLine(estaDisponible);

La palabra clave var

C# también permite declarar una variable usando la palabra clave var, dejando que el compilador infiera (deduzca) el tipo a partir del valor asignado:

var tituloLibro = "Cien anos de soledad"; // el compilador infiere que es 'string'
var numeroPaginas = 471;                  // el compilador infiere que es 'int'
var estaDisponible = true;                // el compilador infiere que es 'bool'

Es muy importante entender que var no convierte a C# en un lenguaje de tipado dinámico: el tipo se sigue fijando en tiempo de compilación, exactamente igual que si lo hubieras escrito de forma explícita; simplemente el compilador lo deduce por ti a partir del valor asignado. Por eso, una vez declarada con var, la variable sigue estando "atada" a ese tipo:

var numeroPaginas = 471;
// numeroPaginas = "cuatrocientas"; // ERROR: no se puede asignar un string a una variable inferida como int
Aspecto Tipo explícito (int x = 5;) var (var x = 5;)
¿Requiere un valor inicial? No Sí, siempre (el compilador necesita el valor para inferir el tipo)
¿El tipo puede cambiar después? No No (una vez inferido, es fijo)
Cuándo usarlo Cuando el tipo aporta claridad al leer el código Cuando el tipo es obvio por el propio valor, o muy largo de escribir

En este curso usaremos ambas formas según el contexto; ninguna es "mejor" de forma absoluta, aunque muchos equipos profesionales prefieren var cuando el tipo es evidente por el valor asignado (como en nuestros ejemplos), y el tipo explícito cuando ayuda a la claridad.

Tipos de valor

Los tipos de valor (value types) son aquellos donde la variable contiene directamente el dato. Cuando copias una variable de tipo valor a otra, se copia el dato completo; cada variable es totalmente independiente de la otra. Los tipos de valor más habituales en C# son los numéricos, el booleano y el carácter:

Tipo Representa Ejemplo Tamaño aproximado
int Número entero 471 32 bits
long Número entero grande 9999999999L 64 bits
double Número decimal (coma flotante) 19.99 64 bits
decimal Número decimal de alta precisión 19.99m 128 bits
bool Valor lógico verdadero/falso true, false 1 bit (lógico)
char Un único carácter 'A' 16 bits

Ejemplo aplicado a BiblioTech:

int numeroPaginas = 471;
double precioLibro = 24.90;
decimal precioExacto = 24.90m;   // el sufijo 'm' indica que es un 'decimal'
bool estaDisponible = true;
char inicialAutor = 'G';

Console.WriteLine(numeroPaginas);
Console.WriteLine(precioLibro);
Console.WriteLine(precioExacto);
Console.WriteLine(estaDisponible);
Console.WriteLine(inicialAutor);

¿double o decimal?

Ambos representan números con decimales, pero tienen un uso distinto:

  • double es más rápido y ocupa menos espacio, pero puede tener pequeñas imprecisiones al hacer ciertas operaciones (por su forma interna de representar los números en binario).
  • decimal es más preciso, pensado específicamente para cálculos donde la exactitud importa mucho, como el dinero (por ejemplo, el precio de un libro o una multa por retraso en BiblioTech). Su sufijo obligatorio es la letra m al final del número literal.

Como norma práctica: para cantidades de dinero, usa siempre decimal; para el resto de cálculos numéricos con decimales, double suele ser suficiente.

Tipos de referencia

A diferencia de los tipos de valor, los tipos de referencia (reference types) no almacenan el dato directamente en la variable, sino una referencia (una especie de "dirección") que apunta a dónde está realmente almacenado el dato. El tipo de referencia más usado, con diferencia, es string:

string tituloLibro = "Cien anos de soledad";
string isbn = "978-0307474728";

La diferencia práctica más importante entre tipos de valor y de referencia aparece al copiar variables:

// Con un tipo de VALOR (int): cada variable es independiente
int paginasLibroA = 471;
int paginasLibroB = paginasLibroA; // se copia el número
paginasLibroB = 500;
Console.WriteLine(paginasLibroA); // sigue mostrando 471: no se ha visto afectada

Con tipos de referencia, veremos en el Módulo 3 (cuando trabajemos con objetos como Libro) que dos variables pueden apuntar al mismo dato en memoria, de forma que modificar uno a través de una variable también afecta a lo que se ve a través de la otra. string es un caso particular de tipo de referencia que se comporta, a efectos prácticos del día a día, de forma muy parecida a un tipo de valor, gracias a su inmutabilidad (que estudiaremos en detalle en la próxima lección): una vez creada una cadena de texto, su contenido no puede modificarse; cualquier operación que "parezca" modificarla en realidad crea una cadena nueva.

Tipos de valor Tipos de referencia
Ejemplos int, double, bool, char, decimal string, arrays, y (Módulo 3) clases definidas por nosotros
Qué contiene la variable El dato directamente Una referencia al dato, almacenado en otro lugar de memoria
Al copiar una variable Se copia el dato completo (independiente) Se copia la referencia (ambas variables pueden apuntar al mismo dato)

No te preocupes si esta distinción no queda completamente clara todavía: la retomaremos con ejemplos mucho más ricos cuando trabajemos con nuestras propias clases en el Módulo 3, donde sus implicaciones se vuelven más visibles.

Conversión de tipos

A veces necesitamos convertir un dato de un tipo a otro: por ejemplo, un número de páginas introducido como texto (string) necesita convertirse a int antes de poder hacer cálculos con él. C# ofrece varias formas de hacerlo.

Conversión implícita

Ocurre automáticamente cuando no hay riesgo de pérdida de información, por ejemplo al pasar de un tipo "más pequeño" a uno "más grande":

int numeroPaginas = 471;
double numeroPaginasComoDecimal = numeroPaginas; // conversión implícita: int -> double, sin pérdida de datos

Conversión explícita (casting)

Es necesaria cuando puede haber pérdida de información (por ejemplo, de double a int, donde se pierden los decimales). Se indica escribiendo el tipo destino entre paréntesis:

double precioConDecimales = 24.90;
int precioRedondeado = (int)precioConDecimales; // conversión explícita: se pierde la parte decimal (queda en 24)

Convert y Parse/TryParse

La conversión más habitual en la práctica es convertir texto (string) a un tipo numérico, por ejemplo cuando se lee un dato introducido por el usuario en la consola:

string textoNumeroPaginas = "471";

// Opción 1: usando la clase Convert
int paginas1 = Convert.ToInt32(textoNumeroPaginas);

// Opción 2: usando el método Parse del propio tipo
int paginas2 = int.Parse(textoNumeroPaginas);

Console.WriteLine(paginas1);
Console.WriteLine(paginas2);

Ambas opciones lanzan un error en tiempo de ejecución si el texto no se puede convertir (por ejemplo, si contiene letras). Para evitar que el programa se detenga abruptamente ante un dato inválido, existe una alternativa más segura: TryParse.

string entradaUsuario = "cuatrocientos"; // un texto no numérico, a modo de ejemplo

bool conversionCorrecta = int.TryParse(entradaUsuario, out int paginas);

if (conversionCorrecta)
{
    Console.WriteLine($"Numero de paginas: {paginas}");
}
else
{
    Console.WriteLine("El texto introducido no es un numero valido.");
}

TryParse devuelve un valor bool indicando si la conversión tuvo éxito, y entrega el resultado a través de un parámetro de salida (out). No te preocupes si la palabra clave out resulta nueva: de momento basta con saber que paginas recibirá el número convertido solo si conversionCorrecta es true. En el Módulo 2, al ver el manejo de excepciones, entenderás mejor por qué TryParse suele ser preferible a Parse cuando el dato viene de una fuente externa (como la entrada del usuario) y no podemos garantizar que sea válido.

Método Comportamiento ante un dato inválido Cuándo usarlo
Convert.ToInt32(texto) Lanza una excepción Cuando confías plenamente en el formato del dato
int.Parse(texto) Lanza una excepción Similar a Convert, específico del tipo
int.TryParse(texto, out valor) Devuelve false, no lanza excepción Cuando el dato puede no ser válido (por ejemplo, entrada de usuario)

Constantes: const y readonly

No todos los datos deben poder cambiar durante la ejecución del programa. Cuando un valor es fijo y conocido de antemano, es buena práctica declararlo como constante, para dejar claro que nunca cambiará y para que el propio compilador impida cualquier intento accidental de modificarlo.

const

Se usa para valores que se conocen ya en tiempo de compilación y nunca van a cambiar:

const int MaximoLibrosPorSocio = 5;
const string NombreSistema = "BiblioTech";

Console.WriteLine($"{NombreSistema} permite un maximo de {MaximoLibrosPorSocio} libros por socio.");
// MaximoLibrosPorSocio = 10; // ERROR: no se puede modificar una constante

readonly

Se usa, sobre todo, en el contexto de clases (Módulo 3) para valores que se fijan una única vez, normalmente al construir el objeto, pero que no se conocen necesariamente en tiempo de compilación (por ejemplo, podrían depender de una fecha o de una entrada externa). Solo lo mencionamos aquí a modo de comparación; su uso real lo veremos con detalle en el Módulo 3 cuando trabajemos con constructores.

const readonly
Se conoce el valor en... Tiempo de compilación Puede fijarse en tiempo de ejecución (una sola vez)
Dónde se usa típicamente Variables locales o de clase con valor fijo Miembros de una clase (Módulo 3)

Ámbito de las variables

El ámbito (scope) de una variable es la región del código donde esa variable existe y puede utilizarse. En C#, el ámbito de una variable local viene determinado por el bloque { } en el que se declara:

{
    int numeroPaginas = 471; // 'numeroPaginas' existe desde aquí...
    Console.WriteLine(numeroPaginas);
} // ...hasta el cierre de este bloque

// Console.WriteLine(numeroPaginas); // ERROR: 'numeroPaginas' ya no existe fuera del bloque

Este comportamiento se volverá muy relevante en el Módulo 2, cuando trabajemos con bloques de if y bucles, ya que las variables declaradas dentro de esos bloques no son visibles fuera de ellos. Por ahora, basta con recordar la regla general: una variable vive dentro de las llaves donde fue declarada, y desaparece al cerrarse ese bloque.

Valores por defecto y nulabilidad básica

Cada tipo de valor tiene un valor por defecto que recibe automáticamente si se declara sin inicializar explícitamente (aunque, en la práctica, C# obliga a inicializar las variables locales antes de usarlas, por lo que este concepto es más relevante en otros contextos, como los campos de una clase que veremos en el Módulo 3):

Tipo Valor por defecto
int, double, decimal 0
bool false
char '\0' (carácter nulo)
string (y otros tipos de referencia) null

¿Qué es null?

null representa la ausencia de un valor: una variable de tipo referencia (como string) puede no apuntar a ningún dato todavía. Por ejemplo, imaginemos un libro de BiblioTech cuyo ISBN todavía no se ha registrado:

string isbnLibro = null; // el libro existe, pero todavía no tiene ISBN asignado
Console.WriteLine(isbnLibro is null); // True

El símbolo ? para tipos de valor nulables

Por defecto, los tipos de valor (int, bool, etc.) no pueden ser null: siempre tienen un valor concreto. Sin embargo, a veces es útil representar "todavía no se sabe" incluso para un número, por ejemplo, el número de páginas de un libro que aún no se ha catalogado completamente. Para ello, C# permite convertir un tipo de valor en nulable añadiendo el símbolo ? después del tipo:

int? numeroPaginas = null; // ahora sí es válido: un 'int?' puede no tener valor
numeroPaginas = 471;       // pero también puede tener un valor normal
Console.WriteLine(numeroPaginas);

Esto es solo una primera toma de contacto con la idea de nulabilidad; en el Módulo 4 profundizaremos en los tipos de referencia nulables (una característica más moderna que extiende esta misma idea a string y otros tipos de referencia, ayudando a prevenir errores relacionados con valores null inesperados). De momento, con saber que ? después de un tipo de valor permite representar "sin valor todavía" es suficiente.

Errores Comunes y Consejos

  • Intentar usar una variable antes de inicializarla: C# no permite leer una variable local que no se ha inicializado; el compilador dará un error. Siempre asigna un valor inicial (aunque sea temporal) antes de usar una variable.
  • Perder precisión al usar double para dinero: por su representación interna en binario, double puede arrastrar pequeñas imprecisiones en cálculos con decimales. Para precios, multas o cualquier cantidad monetaria, usa siempre decimal.
  • Usar Parse con datos que pueden no ser válidos: si el dato viene de fuera (entrada de usuario, un archivo, una API), usa TryParse en lugar de Parse o Convert, para evitar que el programa se detenga con un error si el dato no tiene el formato esperado.
  • Confundir const con una variable normal: una vez declarada una constante, cualquier intento de modificarla es un error de compilación; esto es intencional y forma parte de su utilidad.
  • Consejo: cuando dudes entre var y un tipo explícito, pregúntate si el tipo resulta obvio con solo mirar el valor asignado. Si la respuesta es sí, var suele hacer el código más limpio; si no, el tipo explícito ayuda a la persona que lea el código después.

Ejercicios

  1. Declara tres variables para representar un libro de BiblioTech: su título (string), su número de páginas (int) y si está disponible (bool). Hazlo primero con tipos explícitos y después reescribe las mismas tres declaraciones usando var. Imprime los tres valores con Console.WriteLine.

  2. Un usuario introduce el número de páginas de un libro como texto: string entrada = "350";. Escribe código que convierta ese texto a int de forma segura usando TryParse, y que muestre por consola un mensaje distinto según la conversión tenga éxito o no. Después, prueba a cambiar el valor de entrada por un texto no numérico (por ejemplo, "trescientos") y comprueba que el mensaje de error se muestra correctamente.

  3. Declara una constante const int DiasPrestamoEstandar = 15; que represente los días habituales de préstamo en BiblioTech. Declara también una variable int? diasExtra = null; que representará una posible ampliación del préstamo, todavía no decidida. Escribe el código necesario para, si diasExtra tiene un valor asignado, sumarlo a DiasPrestamoEstandar y mostrar el resultado; si no tiene valor, mostrar solo DiasPrestamoEstandar. (Pista: puedes comprobar diasExtra.HasValue y acceder al valor con diasExtra.Value, o bien usar el operador ?? que asigna un valor por defecto cuando algo es null: diasExtra ?? 0).

Soluciones

  1. Con tipos explícitos:

    string tituloLibro = "Rayuela";
    int numeroPaginas = 635;
    bool estaDisponible = false;
    
    Console.WriteLine(tituloLibro);
    Console.WriteLine(numeroPaginas);
    Console.WriteLine(estaDisponible);
    

    Con var (mismo resultado, tipo inferido automáticamente):

    var tituloLibro = "Rayuela";
    var numeroPaginas = 635;
    var estaDisponible = false;
    
    Console.WriteLine(tituloLibro);
    Console.WriteLine(numeroPaginas);
    Console.WriteLine(estaDisponible);
    
string entrada = "350";

if (int.TryParse(entrada, out int paginas))
{
    Console.WriteLine($"Numero de paginas registrado: {paginas}");
}
else
{
    Console.WriteLine("El valor introducido no es un numero de paginas valido.");
}

Si cambiamos entrada a "trescientos", TryParse devolverá false y se ejecutará la rama del else, mostrando el mensaje de error, sin que el programa se detenga de forma abrupta (a diferencia de lo que ocurriría con int.Parse("trescientos"), que lanzaría una excepción).

const int DiasPrestamoEstandar = 15;
int? diasExtra = null;

int totalDias = DiasPrestamoEstandar + (diasExtra ?? 0);
Console.WriteLine($"Dias totales de prestamo: {totalDias}");

diasExtra = 5; // ahora sí se asigna una ampliación
totalDias = DiasPrestamoEstandar + (diasExtra ?? 0);
Console.WriteLine($"Dias totales de prestamo (con ampliacion): {totalDias}");

El operador ?? (llamado operador de fusión con null) devuelve el valor de la izquierda si no es null, o el de la derecha en caso contrario. Así, cuando diasExtra es null, se suma 0; cuando tiene un valor, se suma ese valor.

Conclusión

En esta lección has aprendido a declarar variables con tipos explícitos y con var, a distinguir entre tipos de valor y tipos de referencia, a convertir datos de un tipo a otro de forma segura, a definir constantes, a entender el ámbito de una variable y a dar tus primeros pasos con la nulabilidad básica. Todos estos conceptos son la base sobre la que se apoyará absolutamente todo el código que escribas en los próximos módulos, empezando por las clases que definiremos en el Módulo 3 (Libro, Socio, Prestamo), que no son más que un conjunto organizado de variables (llamadas ahí "campos" o "propiedades") y de comportamiento asociado.

En la siguiente y última lección de este módulo, Arrays y Cadenas de Texto, aprenderás a trabajar con colecciones de datos (por ejemplo, varios títulos de libros a la vez) usando arrays, y a manipular texto en profundidad con la clase string, incluyendo interpolación, búsquedas y transformaciones habituales.

Curso de Programación en C#

Módulo 1: Introducción a C#

Módulo 2: Estructuras de Control

Módulo 3: Programación Orientada a Objetos

Módulo 4: Conceptos Avanzados de C#

Módulo 5: Trabajando con Datos

Módulo 6: Temas Avanzados

Módulo 7: Construcción de Aplicaciones

Módulo 8: Mejores Prácticas y Patrones de Diseño

Módulo 9: Proyecto Final

© Copyright 2026. Todos los derechos reservados