CSharp

Tutorial CSharp: Funciones

Aprende a crear funciones en C# con parámetros y retorno. Domina la sintaxis básica y buenas prácticas para código modular y reutilizable.

Aprende CSharp y certifícate

Sintaxis básica de una función

En C#, las funciones (también llamadas métodos) son bloques de código que realizan una tarea específica y pueden ser reutilizados en diferentes partes de un programa. Las funciones nos permiten organizar nuestro código de manera más eficiente, evitando la repetición y mejorando la legibilidad.

La sintaxis básica para definir una función en C# sigue un patrón claro y estructurado:

tipoDeRetorno NombreDeLaFuncion()
{
    // Cuerpo de la función
    // Código que se ejecutará cuando la función sea llamada
    
    return valorDeRetorno; // Opcional, dependiendo del tipo de retorno
}

Vamos a analizar cada parte de esta estructura:

  • Modificador de acceso: Determina la visibilidad de la función. Aunque no es obligatorio, es común especificarlo. Los más comunes son:

  • public: Accesible desde cualquier parte del programa

  • private: Solo accesible dentro de la misma clase

  • protected: Accesible dentro de la clase y sus derivadas

  • internal: Accesible dentro del mismo ensamblado

  • Tipo de retorno: Indica qué tipo de dato devolverá la función. Puede ser cualquier tipo válido en C# (int, string, bool, etc.) o void si la función no devuelve ningún valor.

  • Nombre de la función: Debe ser un identificador válido en C#. Por convención, se utiliza PascalCase (primera letra de cada palabra en mayúscula).

  • Paréntesis (): Pueden contener parámetros (que veremos en la siguiente sección) o estar vacíos.

  • Cuerpo de la función: Delimitado por llaves {}, contiene el código que se ejecutará cuando la función sea llamada.

  • Instrucción return: Si la función tiene un tipo de retorno distinto de void, debe incluir al menos una instrucción return que devuelva un valor del tipo especificado.

Veamos algunos ejemplos básicos:

Ejemplo 1: Una función simple que no recibe parámetros y no devuelve ningún valor:

public void MostrarMensaje()
{
    Console.WriteLine("¡Hola desde mi primera función!");
}

Para llamar o invocar esta función, simplemente escribimos su nombre seguido de paréntesis:

MostrarMensaje(); // Imprime: ¡Hola desde mi primera función!

Ejemplo 2: Una función que devuelve un valor:

public int ObtenerNumeroAleatorio()
{
    Random random = new Random();
    int numero = random.Next(1, 101); // Genera un número entre 1 y 100
    return numero;
}

Para usar esta función y capturar su valor de retorno:

int miNumero = ObtenerNumeroAleatorio();
Console.WriteLine($"El número aleatorio es: {miNumero}");

Ejemplo 3: Una función con modificador de acceso privado:

private bool EsFinDeSemana()
{
    DayOfWeek diaDeLaSemana = DateTime.Now.DayOfWeek;
    return diaDeLaSemana == DayOfWeek.Saturday || diaDeLaSemana == DayOfWeek.Sunday;
}

Esta función solo puede ser llamada desde dentro de la misma clase donde está definida.

Ubicación de las funciones en C#

En C#, las funciones siempre deben estar definidas dentro de una clase. No pueden existir de forma independiente como en otros lenguajes. Un ejemplo completo sería:

using System;

class Programa
{
    // Método principal (punto de entrada)
    static void Main()
    {
        SaludarUsuario();
        
        bool esFinde = EsFinDeSemana();
        Console.WriteLine($"¿Es fin de semana? {esFinde}");
    }
    
    // Función sin valor de retorno
    static void SaludarUsuario()
    {
        Console.WriteLine("¡Bienvenido a mi programa!");
    }
    
    // Función con valor de retorno
    static bool EsFinDeSemana()
    {
        DayOfWeek dia = DateTime.Now.DayOfWeek;
        return dia == DayOfWeek.Saturday || dia == DayOfWeek.Sunday;
    }
}

Observa que en este ejemplo hemos añadido el modificador static a nuestras funciones. Esto es necesario para poder llamarlas desde el método Main (que también es static). El modificador static indica que la función pertenece a la clase en sí, no a una instancia específica de la clase.

Buenas prácticas al definir funciones

  • Usa nombres descriptivos que indiquen claramente lo que hace la función.
  • Sigue la convención de PascalCase para los nombres de funciones.
  • Cada función debe realizar una única tarea bien definida.
  • Mantén las funciones cortas y concisas. Si una función es muy larga, considera dividirla en funciones más pequeñas.
  • Documenta tus funciones con comentarios cuando sea necesario, especialmente si su propósito no es obvio.
/// <summary>
/// Calcula el área de un círculo dado su radio.
/// </summary>
/// <param name="radio">El radio del círculo en unidades.</param>
/// <returns>El área del círculo en unidades cuadradas.</returns>
public double CalcularAreaCirculo(double radio)
{
    return Math.PI * radio * radio;
}

Con estos fundamentos, ya estás listo para crear y utilizar funciones básicas en C#. En las siguientes secciones, aprenderemos cómo trabajar con parámetros y valores de retorno de manera más avanzada.

Parámetros en funciones

Los parámetros son una parte fundamental de las funciones en C# que nos permiten enviar datos a una función para que trabaje con ellos. Gracias a los parámetros, nuestras funciones se vuelven más flexibles y reutilizables, ya que pueden operar con diferentes valores cada vez que las llamamos.

La sintaxis para definir parámetros es sencilla: se colocan dentro de los paréntesis de la declaración de la función, especificando el tipo de dato y un nombre para cada parámetro:

tipoDeRetorno NombreFuncion(tipoDato1 nombreParametro1, tipoDato2 nombreParametro2)
{
    // Código que utiliza los parámetros
}

Parámetros simples

Veamos un ejemplo básico de una función con un parámetro:

static void Saludar(string nombre)
{
    Console.WriteLine($"¡Hola, {nombre}!");
}

Para llamar a esta función, debemos proporcionar un argumento que coincida con el tipo de parámetro esperado:

Saludar("Ana");    // Imprime: ¡Hola, Ana!
Saludar("Carlos"); // Imprime: ¡Hola, Carlos!

Múltiples parámetros

Las funciones pueden recibir varios parámetros, separados por comas:

static void MostrarInformacion(string nombre, int edad)
{
    Console.WriteLine($"{nombre} tiene {edad} años.");
}

Al llamar a la función, debemos proporcionar todos los argumentos en el mismo orden:

MostrarInformacion("Laura", 28); // Imprime: Laura tiene 28 años.

Parámetros con valores predeterminados

C# permite definir valores predeterminados para los parámetros. Estos valores se utilizarán cuando no se proporcione un argumento para ese parámetro:

static void ConfigurarUsuario(string nombre, bool esAdmin = false)
{
    if (esAdmin)
        Console.WriteLine($"{nombre} tiene permisos de administrador.");
    else
        Console.WriteLine($"{nombre} tiene permisos estándar.");
}

Esta función puede llamarse de dos maneras:

ConfigurarUsuario("Miguel");           // Usa el valor predeterminado false
// Imprime: Miguel tiene permisos estándar.

ConfigurarUsuario("Elena", true);      // Sobrescribe el valor predeterminado
// Imprime: Elena tiene permisos de administrador.

Parámetros nombrados

Los parámetros nombrados nos permiten especificar a qué parámetro corresponde cada argumento, independientemente del orden:

static void CalcularEnvio(string destino, double peso, bool esUrgente = false)
{
    double costo = peso * 2.5;
    if (esUrgente) costo *= 1.5;
    
    Console.WriteLine($"Envío a {destino} - Peso: {peso}kg - Costo: ${costo}");
}

Podemos llamar a esta función de varias formas:

// Forma tradicional
CalcularEnvio("Madrid", 3.5, true);

// Usando parámetros nombrados
CalcularEnvio(destino: "Barcelona", peso: 2.0, esUrgente: false);

// Cambiando el orden con parámetros nombrados
CalcularEnvio(esUrgente: true, peso: 1.5, destino: "Valencia");

// Combinando parámetros posicionales y nombrados
CalcularEnvio("Sevilla", peso: 4.2);

Los parámetros nombrados son especialmente útiles cuando una función tiene muchos parámetros o varios parámetros opcionales.

Parámetros de salida (out)

Los parámetros marcados con la palabra clave out permiten que una función devuelva múltiples valores:

static void DividirConResto(int dividendo, int divisor, out int cociente, out int resto)
{
    cociente = dividendo / divisor;
    resto = dividendo % divisor;
}

Para usar esta función:

int resultado, residuo;
DividirConResto(17, 5, out resultado, out residuo);
Console.WriteLine($"17 ÷ 5 = {resultado} con resto {residuo}");
// Imprime: 17 ÷ 5 = 3 con resto 2

También podemos declarar las variables directamente en la llamada:

DividirConResto(17, 5, out int resultado, out int residuo);

Parámetros de referencia (ref)

La palabra clave ref indica que un parámetro se pasa por referencia, lo que permite modificar el valor original:

static void Duplicar(ref int numero)
{
    numero *= 2;
}

Para usar esta función:

int valor = 5;
Console.WriteLine($"Valor original: {valor}");  // Imprime: Valor original: 5

Duplicar(ref valor);
Console.WriteLine($"Valor duplicado: {valor}"); // Imprime: Valor duplicado: 10

La diferencia principal entre ref y out es que con ref la variable debe estar inicializada antes de pasarla a la función, mientras que con out no es necesario.

Número variable de parámetros (params)

La palabra clave params permite que una función acepte un número variable de argumentos del mismo tipo:

static double Promedio(params int[] numeros)
{
    int suma = 0;
    foreach (int num in numeros)
    {
        suma += num;
    }
    
    return (double)suma / numeros.Length;
}

Esta función puede llamarse con cualquier cantidad de argumentos:

double media1 = Promedio(5, 10, 15);
Console.WriteLine($"Promedio 1: {media1}");  // Imprime: Promedio 1: 10

double media2 = Promedio(2, 4, 6, 8, 10);
Console.WriteLine($"Promedio 2: {media2}");  // Imprime: Promedio 2: 6

También podemos pasar un array directamente:

int[] valores = { 1, 2, 3, 4, 5 };
double media3 = Promedio(valores);

Buenas prácticas con parámetros

  • Limita el número de parámetros: Una función con demasiados parámetros puede ser difícil de usar. Si necesitas muchos parámetros, considera usar una clase o estructura.

  • Usa nombres descriptivos: Los nombres de los parámetros deben indicar claramente qué representan.

  • Valida los parámetros: Verifica que los valores recibidos sean válidos antes de usarlos.

static double CalcularAreaRectangulo(double ancho, double alto)
{
    if (ancho <= 0 || alto <= 0)
    {
        throw new ArgumentException("Las dimensiones deben ser positivas");
    }
    
    return ancho * alto;
}
  • Considera la inmutabilidad: Evita modificar los parámetros de entrada a menos que sea necesario y esté claramente indicado (como con ref o out).

Los parámetros son una herramienta esencial que hace que nuestras funciones sean verdaderamente útiles y versátiles. Dominar los diferentes tipos de parámetros te permitirá crear código más flexible y reutilizable en tus aplicaciones C#.

Retorno de función

El retorno de una función es el mecanismo mediante el cual una función puede devolver un valor al código que la llamó. Esta característica es fundamental en la programación ya que permite que las funciones no solo realicen acciones, sino que también produzcan resultados que pueden ser utilizados posteriormente en el programa.

En C#, el tipo de retorno de una función se especifica antes del nombre de la función en su declaración. Este tipo puede ser cualquier tipo de dato válido en C#, incluyendo tipos primitivos (como int, double, bool), tipos de referencia (como string, array), o incluso tipos definidos por el usuario.

Funciones con retorno de valor

Para crear una función que devuelva un valor, debemos:

  1. Especificar el tipo de dato que devolverá la función
  2. Utilizar la palabra clave return seguida del valor a devolver
static int Sumar(int a, int b)
{
    int resultado = a + b;
    return resultado;
}

También podemos simplificar esta función:

static int Sumar(int a, int b)
{
    return a + b;
}

Para utilizar el valor devuelto por una función, simplemente asignamos la llamada a una variable del tipo adecuado:

int suma = Sumar(5, 3);
Console.WriteLine($"La suma es: {suma}");  // Imprime: La suma es: 8

También podemos usar el valor directamente en una expresión:

Console.WriteLine($"El doble de la suma es: {Sumar(5, 3) * 2}");  // Imprime: El doble de la suma es: 16

Funciones sin valor de retorno (void)

Cuando una función no necesita devolver ningún valor, utilizamos el tipo especial void:

static void MostrarMensaje(string mensaje)
{
    Console.WriteLine(mensaje);
    // No hay instrucción return con valor
}

Las funciones void pueden terminar su ejecución de dos formas:

  1. Cuando se llega al final del cuerpo de la función
  2. Mediante una instrucción return sin valor
static void VerificarEdad(int edad)
{
    if (edad < 0)
    {
        Console.WriteLine("La edad no puede ser negativa");
        return;  // Termina la ejecución de la función
    }
    
    Console.WriteLine($"La edad es: {edad} años");
}

Retorno de diferentes tipos de datos

Las funciones pueden devolver cualquier tipo de dato en C#:

Tipos numéricos:

static double CalcularPromedio(int[] numeros)
{
    int suma = 0;
    foreach (int num in numeros)
    {
        suma += num;
    }
    
    return (double)suma / numeros.Length;
}

Tipos booleanos:

static bool EsNumeroValido(int numero)
{
    return numero >= 0 && numero <= 100;
}

Cadenas de texto:

static string ObtenerSaludo(string nombre)
{
    return $"¡Hola, {nombre}! Bienvenido/a.";
}

Arrays:

static int[] GenerarSecuencia(int inicio, int fin)
{
    int longitud = fin - inicio + 1;
    int[] secuencia = new int[longitud];
    
    for (int i = 0; i < longitud; i++)
    {
        secuencia[i] = inicio + i;
    }
    
    return secuencia;
}

Múltiples instrucciones return

Una función puede tener múltiples instrucciones return, pero solo se ejecutará una de ellas:

static string ClasificarNumero(int numero)
{
    if (numero < 0)
    {
        return "Negativo";
    }
    else if (numero == 0)
    {
        return "Cero";
    }
    else
    {
        return "Positivo";
    }
}

Retorno implícito en expresiones lambda

En C# también podemos crear funciones más concisas utilizando expresiones lambda con retorno implícito:

// Función tradicional
static int Cuadrado(int n)
{
    return n * n;
}

// Equivalente con expresión lambda
static int CuadradoLambda(int n) => n * n;

Uso práctico de funciones con retorno

Veamos un ejemplo práctico que combina varias funciones con diferentes tipos de retorno:

static void Main()
{
    // Solicitar datos al usuario
    Console.Write("Ingrese la temperatura en Celsius: ");
    double celsius = Convert.ToDouble(Console.ReadLine());
    
    // Convertir temperatura
    double fahrenheit = CelsiusAFahrenheit(celsius);
    
    // Mostrar resultado
    Console.WriteLine($"{celsius}°C equivale a {fahrenheit}°F");
    
    // Clasificar la temperatura
    string sensacion = ClasificarTemperatura(celsius);
    Console.WriteLine($"Sensación térmica: {sensacion}");
}

static double CelsiusAFahrenheit(double celsius)
{
    return (celsius * 9 / 5) + 32;
}

static string ClasificarTemperatura(double celsius)
{
    if (celsius < 0)
    {
        return "Muy frío";
    }
    else if (celsius < 10)
    {
        return "Frío";
    }
    else if (celsius < 25)
    {
        return "Templado";
    }
    else if (celsius < 30)
    {
        return "Cálido";
    }
    else
    {
        return "Muy caliente";
    }
}

Buenas prácticas para el retorno de funciones

  • Coherencia en el tipo de retorno: Asegúrate de que el tipo de retorno sea coherente con lo que la función debe devolver.

  • Nombres descriptivos: El nombre de la función debe indicar claramente qué valor devuelve.

// Buen nombre para una función que devuelve un booleano
static bool EsNumeroPrimo(int numero)

// Buen nombre para una función que devuelve un valor
static double CalcularImpuesto(double precio)
  • Evita efectos secundarios: Una función que devuelve un valor debería centrarse en calcular ese valor, no en realizar otras acciones como modificar variables globales o mostrar mensajes.

  • Validación de datos: Considera qué debe devolver la función en casos excepcionales.

static int DividirSeguro(int dividendo, int divisor)
{
    if (divisor == 0)
    {
        // Podríamos lanzar una excepción, pero para simplificar:
        return 0;  // O algún otro valor que indique error
    }
    
    return dividendo / divisor;
}
  • Consistencia en los valores de retorno: Si una función puede devolver un error, mantén un enfoque consistente (usar excepciones, códigos de error, etc.).

El uso efectivo del retorno de funciones te permitirá crear código más modular, reutilizable y fácil de mantener. Las funciones bien diseñadas que devuelven valores apropiados son la base de un código limpio y estructurado en C#.

Aprende CSharp online

Otros ejercicios de programación de CSharp

Evalúa tus conocimientos de esta lección Funciones con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de CSharp

Accede a todas las lecciones de CSharp y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A C#

Introducción Y Entorno

Creación De Proyecto C#

Introducción Y Entorno

Variables Y Constantes

Sintaxis

Tipos De Datos

Sintaxis

Operadores

Sintaxis

Control De Flujo

Sintaxis

Funciones

Sintaxis

Estructuras De Control Iterativo

Sintaxis

Interpolación De Strings

Sintaxis

Estructuras De Control Condicional

Sintaxis

Manejo De Valores Nulos

Sintaxis

Clases Y Encapsulación

Programación Orientada A Objetos

Objetos

Programación Orientada A Objetos

Constructores Y Destructores

Programación Orientada A Objetos

Herencia

Programación Orientada A Objetos

Polimorfismo

Programación Orientada A Objetos

Genéricos

Programación Orientada A Objetos

Métodos Virtuales Y Sobrecarga

Programación Orientada A Objetos

Clases Abstractas

Programación Orientada A Objetos

Interfaces

Programación Orientada A Objetos

Propiedades Y Encapsulación

Programación Orientada A Objetos

Métodos De Extensión

Programación Orientada A Objetos

Clases Y Objetos

Programación Orientada A Objetos

Clases Parciales

Programación Orientada A Objetos

Miembros Estáticos

Programación Orientada A Objetos

Tuplas Y Tipos Anónimos

Programación Orientada A Objetos

Arrays Y Listas

Colecciones Y Linq

Diccionarios

Colecciones Y Linq

Conjuntos, Colas Y Pilas

Colecciones Y Linq

Uso De Consultas Linq

Colecciones Y Linq

Linq Avanzado

Colecciones Y Linq

Colas Y Pilas

Colecciones Y Linq

Conjuntos

Colecciones Y Linq

Linq Básico

Colecciones Y Linq

Delegados Funcionales

Programación Funcional

Records

Programación Funcional

Expresiones Lambda

Programación Funcional

Linq Funcional

Programación Funcional

Fundamentos De La Programación Funcional

Programación Funcional

Pattern Matching

Programación Funcional

Testing Unitario Con Xunit

Testing

Excepciones

Excepciones

Delegados

Programación Asíncrona

Eventos

Programación Asíncrona

Lambdas

Programación Asíncrona

Uso De Async Y Await

Programación Asíncrona

Tareas

Programación Asíncrona

Accede GRATIS a CSharp y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender la sintaxis básica para definir funciones en C#.
  • Aprender a utilizar diferentes tipos de parámetros, incluyendo valores predeterminados, nombrados, out, ref y params.
  • Entender cómo funcionan los valores de retorno en funciones y su importancia.
  • Conocer las buenas prácticas para definir funciones claras, concisas y reutilizables.
  • Saber cómo organizar funciones dentro de clases y el uso del modificador static.