Módulo 07: Funciones y métodos
Objetivos del módulo
- Comprender qué es una función (método) y por qué usarla
- Crear funciones con y sin valor de retorno
- Dominar los parámetros:
ref,out,params, opcionales - Entender la sobrecarga de métodos
- Aplicar recursividad
- Usar tuplas como retorno múltiple
1. ¿Qué es una función?
📘 Concepto: Una función (o método) es un bloque de código reutilizable con un nombre, que realiza una tarea específica. En lugar de repetir el mismo código, lo encapsulas en una función y la llamas por su nombre.
Beneficios
- Reutilización: escribes una vez, usas muchas
- Organización: divides el programa en partes lógicas
- Mantenimiento: si hay un error, lo corriges en un solo lugar
- Legibilidad: el código se lee como instrucciones de alto nivel
2. Estructura de una función
static int Sumar(int a, int b)
{
return a + b;
}
Explicación de cada parte:
| Parte | Significado |
|---|---|
static | Pertenece al programa directamente (no a un objeto). Lo usamos en top-level statements |
int | Tipo de retorno: qué tipo de dato devuelve la función |
Sumar | Nombre de la función (PascalCase por convención) |
(int a, int b) | Parámetros: datos que la función recibe para trabajar |
return a + b; | Instrucción return: devuelve el resultado al código que la llamó |
Llamar a la función
int resultado = Sumar(5, 3); // resultado = 8
Console.WriteLine(resultado);
// También puedes usar el resultado directamente
Console.WriteLine(Sumar(10, 20)); // 30
3. Funciones sin valor de retorno (void)
Cuando una función solo hace algo (como imprimir) pero no devuelve ningún dato, su tipo de retorno es void:
static void Saludar(string nombre)
{
Console.WriteLine($"¡Hola, {nombre}! Bienvenido.");
}
// Llamada
Saludar("Ana"); // ¡Hola, Ana! Bienvenido.
Saludar("Luis"); // ¡Hola, Luis! Bienvenido.
⚠️ Importante: Las funciones
voidno usanreturncon valor. Pueden usarreturn;(sin valor) para salir antes de tiempo.
static void MostrarSiPositivo(int numero)
{
if (numero <= 0)
{
return; // Sale de la función, no hace nada más
}
Console.WriteLine($"El número {numero} es positivo");
}
4. Parámetros y argumentos
📘 Concepto: Los parámetros son las variables que defines en la declaración de la función. Los argumentos son los valores concretos que pasas al llamarla.
// parámetros
static int Multiplicar(int a, int b)
{
return a * b;
}
// argumentos
int resultado = Multiplicar(5, 3);
Paso por valor (por defecto)
Por defecto, los parámetros se pasan por valor: la función recibe una copia del dato. Si la función modifica el parámetro, no afecta a la variable original.
static void Duplicar(int numero)
{
numero = numero * 2;
Console.WriteLine($"Dentro de la función: {numero}"); // 20
}
int x = 10;
Duplicar(x);
Console.WriteLine($"Fuera de la función: {x}"); // 10 ← ¡No cambió!
Paso por referencia: ref
Con ref, la función trabaja directamente con la variable original, no con una copia:
static void Duplicar(ref int numero)
{
numero = numero * 2;
}
int x = 10;
Duplicar(ref x); // ← También necesitas 'ref' al llamar
Console.WriteLine(x); // 20 ← ¡Ahora sí cambió!
⚠️ Importante: La variable que pasas con
refdebe estar inicializada antes de pasarla.
Parámetros de salida: out
Similar a ref, pero está diseñado para que la función devuelva datos adicionales a través del parámetro. La variable no necesita estar inicializada.
static bool DividirSeguro(int a, int b, out double resultado)
{
if (b == 0)
{
resultado = 0; // out exige asignar un valor siempre
return false;
}
resultado = (double)a / b;
return true;
}
// Uso
if (DividirSeguro(10, 3, out double res))
{
Console.WriteLine($"Resultado: {res:F2}"); // 3.33
}
else
{
Console.WriteLine("No se puede dividir entre cero");
}
💡 Consejo: Ya has visto
outen acción conint.TryParse(texto, out int numero). Ahora sabes cómo funciona internamente.
params: número variable de argumentos
params permite pasar cualquier cantidad de argumentos del mismo tipo:
static int Sumar(params int[] numeros)
{
int total = 0;
foreach (int n in numeros)
{
total += n;
}
return total;
}
// Puedes pasar cualquier cantidad de argumentos
Console.WriteLine(Sumar(1, 2)); // 3
Console.WriteLine(Sumar(1, 2, 3, 4, 5)); // 15
Console.WriteLine(Sumar()); // 0
// También puedes pasar un array directamente
int[] nums = { 10, 20, 30 };
Console.WriteLine(Sumar(nums)); // 60
Parámetros con valor por defecto (opcionales)
Puedes dar un valor predeterminado a un parámetro. Si no le pasas un argumento, usa ese valor:
static void Saludar(string nombre, string saludo = "Hola")
{
Console.WriteLine($"{saludo}, {nombre}!");
}
Saludar("Ana"); // Hola, Ana!
Saludar("Ana", "Buenos días"); // Buenos días, Ana!
⚠️ Importante: Los parámetros opcionales siempre van al final de la lista de parámetros.
Argumentos con nombre
Puedes pasar argumentos usando el nombre del parámetro. Muy útil con funciones que tienen muchos parámetros:
static void CrearUsuario(string nombre, int edad, string ciudad = "Madrid")
{
Console.WriteLine($"{nombre}, {edad} años, {ciudad}");
}
// Argumentos por posición (normal)
CrearUsuario("Ana", 25, "Barcelona");
// Argumentos con nombre (puedes cambiar el orden)
CrearUsuario(edad: 30, nombre: "Luis", ciudad: "Sevilla");
// Saltar opcionales con argumentos con nombre
CrearUsuario("María", 22); // ciudad = "Madrid" (valor por defecto)
5. Sobrecarga de métodos (Overloading)
📘 Concepto: La sobrecarga permite crear varias funciones con el mismo nombre pero con diferentes parámetros (distinto número o tipo de parámetros). C# elige cuál ejecutar según los argumentos.
static double CalcularArea(double radio)
{
return Math.PI * radio * radio; // Área del círculo
}
static double CalcularArea(double ancho, double alto)
{
return ancho * alto; // Área del rectángulo
}
static double CalcularArea(double baseTriang, double altura, bool esTriangulo)
{
return baseTriang * altura / 2; // Área del triángulo
}
// C# elige automáticamente cuál usar según los argumentos
Console.WriteLine($"Círculo: {CalcularArea(5.0):F2}"); // 78.54
Console.WriteLine($"Rectángulo: {CalcularArea(4.0, 6.0):F2}"); // 24.00
Console.WriteLine($"Triángulo: {CalcularArea(3.0, 8.0, true):F2}"); // 12.00
6. Variables locales y ámbito (scope)
📘 Concepto: Las variables declaradas dentro de una función solo existen dentro de esa función. Esto se llama ámbito o scope.
static void FuncionA()
{
int x = 10; // x solo existe dentro de FuncionA
Console.WriteLine(x);
}
static void FuncionB()
{
// Console.WriteLine(x); // ERROR: x no existe aquí
int x = 20; // Esta es OTRA variable x, diferente
Console.WriteLine(x);
}
FuncionA(); // 10
FuncionB(); // 20
7. Recursividad
📘 Concepto: Una función recursiva es aquella que se llama a sí misma. Siempre necesita un caso base (condición de parada) para no ejecutarse infinitamente.
Ejemplo: factorial
5! = 5 × 4 × 3 × 2 × 1 = 120
static long Factorial(int n)
{
// Caso base: condición de parada
if (n <= 1)
{
return 1;
}
// Caso recursivo: la función se llama a sí misma
return n * Factorial(n - 1);
}
Console.WriteLine(Factorial(5)); // 120
Console.WriteLine(Factorial(10)); // 3628800
Traza de ejecución:
Factorial(5)
→ 5 * Factorial(4)
→ 4 * Factorial(3)
→ 3 * Factorial(2)
→ 2 * Factorial(1)
→ 1 (caso base)
→ 2 * 1 = 2
→ 3 * 2 = 6
→ 4 * 6 = 24
→ 5 * 24 = 120
Ejemplo: Fibonacci
static long Fibonacci(int n)
{
if (n <= 0) return 0;
if (n == 1) return 1;
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
for (int i = 0; i < 10; i++)
{
Console.Write($"{Fibonacci(i)} "); // 0 1 1 2 3 5 8 13 21 34
}
⚠️ Importante: La recursividad es elegante pero puede ser ineficiente para valores grandes (Fibonacci recursivo tiene complejidad exponencial). Para problemas reales, a menudo un bucle es mejor.
8. Tuplas como retorno múltiple
Las tuplas permiten devolver varios valores desde una función sin crear una clase:
static (double min, double max, double media) Estadisticas(int[] numeros)
{
double min = numeros.Min();
double max = numeros.Max();
double media = numeros.Average();
return (min, max, media);
}
int[] datos = { 4, 8, 15, 16, 23, 42 };
var stats = Estadisticas(datos);
Console.WriteLine($"Mínimo: {stats.min}"); // 4
Console.WriteLine($"Máximo: {stats.max}"); // 42
Console.WriteLine($"Media: {stats.media:F2}"); // 18.00
// Desestructuración directa
var (minimo, maximo, media) = Estadisticas(datos);
Console.WriteLine($"Min={minimo}, Max={maximo}, Media={media:F2}");
9. Funciones locales
C# permite definir funciones dentro de otras funciones:
static bool EsNumeroPrimo(int n)
{
if (n < 2) return false;
// Función local: solo existe dentro de EsNumeroPrimo
bool TieneDivisor(int limite)
{
for (int i = 2; i <= limite; i++)
{
if (n % i == 0) return true;
}
return false;
}
return !TieneDivisor((int)Math.Sqrt(n));
}
for (int i = 1; i <= 20; i++)
{
if (EsNumeroPrimo(i))
Console.Write($"{i} "); // 2 3 5 7 11 13 17 19
}
10. Funciones de expresión (expression-bodied)
Cuando una función tiene una sola expresión, puedes usar la sintaxis =>:
// Forma normal
static int Sumar(int a, int b)
{
return a + b;
}
// Expression-bodied (una línea)
static int Sumar(int a, int b) => a + b;
// Más ejemplos
static double AreaCirculo(double r) => Math.PI * r * r;
static bool EsPar(int n) => n % 2 == 0;
static string Saludar(string nombre) => $"Hola, {nombre}!";
static void Despedir() => Console.WriteLine("¡Adiós!");
11. Ejercicios
Ejercicio 1: Calculadora con funciones
Crea una calculadora donde cada operación (Sumar, Restar, Multiplicar, Dividir) sea una función separada. El programa muestra un menú, pide dos números y la operación.
Ejercicio 2: Conversor de temperaturas
Crea funciones:
CelsiusAFahrenheit(double celsius)→ retorna FahrenheitFahrenheitACelsius(double fahrenheit)→ retorna CelsiusCelsiusAKelvin(double celsius)→ retorna Kelvin
Ejercicio 3: Funciones estadísticas
Sin usar LINQ, crea funciones que reciban un int[] y devuelvan: Minimo, Maximo, Media, Mediana, Moda. Usa una función Estadisticas que devuelva todo en una tupla.
Ejercicio 4: Torres de Hanoi
Implementa el clásico problema de las Torres de Hanoi con recursividad. El programa debe mostrar cada movimiento: “Mover disco 1 de A a C”.
Ejercicio 5: Mini juego de adivinanza
Crea un juego donde el ordenador elige un número aleatorio (1-100) y el usuario lo adivina. Usa funciones separadas para:
GenerarNumero()→ genera un número aleatorioPedirIntento()→ pide un número al usuario con validaciónComprobarIntento(int secreto, int intento)→ devuelve una tupla(bool acerto, string pista)
Resumen
| Concepto | Sintaxis |
|---|---|
| Función con retorno | static int Func(int a) { return a; } |
| Función void | static void Func() { } |
| Paso por referencia | static void Func(ref int x) |
| Parámetro de salida | static void Func(out int x) |
| Número variable | static void Func(params int[] arr) |
| Opcional | static void Func(int x = 10) |
| Sobrecarga | Mismo nombre, diferentes parámetros |
| Recursividad | Función que se llama a sí misma |
| Tupla retorno | static (int, string) Func() |
| Expression body | static int Func(int x) => x * 2; |