CSharp

Tutorial CSharp: Lambdas

Aprende la sintaxis y uso de lambdas en C# para funciones anónimas, colecciones, LINQ y programación asíncrona con ejemplos prácticos.

Aprende CSharp y certifícate

Sintaxis básica

Las expresiones lambda en C# son una forma concisa de representar funciones anónimas, es decir, métodos sin nombre que pueden definirse en línea. Estas expresiones proporcionan una sintaxis simplificada que resulta especialmente útil cuando necesitamos crear funciones pequeñas y específicas sin tener que declarar un método completo.

La sintaxis básica de una expresión lambda se compone de tres elementos principales:

(parámetros) => expresión_o_bloque

Donde:

  • Los parámetros son las entradas que recibe la función
  • El operador => (conocido como operador lambda o "va a")
  • La expresión o bloque que define lo que hace la función

Veamos algunos ejemplos sencillos para entender mejor esta sintaxis:

Lambda con un parámetro

// Lambda que recibe un número y devuelve su cuadrado
Func<int, int> cuadrado = x => x * x;

// Uso:
int resultado = cuadrado(5); // resultado = 25

En este ejemplo, x es el parámetro de entrada y x * x es la expresión que se evalúa y devuelve.

Lambda con múltiples parámetros

// Lambda que suma dos números
Func<int, int, int> sumar = (a, b) => a + b;

// Uso:
int suma = sumar(3, 4); // suma = 7

Cuando tenemos más de un parámetro, debemos encerrarlos entre paréntesis.

Lambda sin parámetros

// Lambda sin parámetros que devuelve un saludo
Func<string> saludo = () => "Hola mundo";

// Uso:
string mensaje = saludo(); // mensaje = "Hola mundo"

Lambda con bloque de código

Cuando necesitamos incluir más de una instrucción, podemos usar llaves para crear un bloque de código:

// Lambda con bloque de código
Func<int, int> factorial = n =>
{
    int resultado = 1;
    for (int i = 1; i <= n; i++)
    {
        resultado *= i;
    }
    return resultado;
};

// Uso:
int fact5 = factorial(5); // fact5 = 120

En este caso, como estamos usando un bloque de código con múltiples instrucciones, necesitamos incluir explícitamente la palabra clave return para devolver un valor.

Tipos de parámetros

En muchos casos, C# puede inferir automáticamente los tipos de los parámetros de la lambda:

// El compilador infiere que x es un entero
Func<int, bool> esPar = x => x % 2 == 0;

Sin embargo, también podemos especificar explícitamente los tipos:

// Especificando explícitamente el tipo del parámetro
Func<int, bool> esPar = (int x) => x % 2 == 0;

Especificar los tipos puede ser necesario en situaciones donde el compilador no puede inferirlos correctamente o cuando queremos mejorar la legibilidad del código.

Captura de variables

Una característica importante de las lambdas es que pueden capturar variables del ámbito donde se definen:

int factor = 10;
Func<int, int> multiplicar = x => x * factor;

int resultado = multiplicar(5); // resultado = 50

En este ejemplo, la lambda captura la variable factor del ámbito exterior y la utiliza en su expresión.

Las expresiones lambda en C# proporcionan una forma elegante y concisa de definir pequeñas funciones, especialmente útiles cuando necesitamos pasar comportamiento como argumento a otros métodos, como veremos en la siguiente sección sobre "Lambdas como argumentos".

Lambdas como argumentos

Una de las ventajas principales de las expresiones lambda es su capacidad para ser pasadas como argumentos a otros métodos. Esta característica resulta especialmente útil cuando trabajamos con métodos que esperan delegados o interfaces funcionales como parámetros.

En C#, muchos métodos de las colecciones y LINQ (Language Integrated Query) están diseñados para recibir funciones como argumentos, y las lambdas son perfectas para este propósito. Veamos algunos escenarios comunes donde las lambdas brillan como argumentos:

Uso con métodos de colecciones

Las colecciones en C# incluyen varios métodos que aceptan predicados (funciones que devuelven un valor booleano) u otras funciones como argumentos:

List<int> numeros = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// Filtrar números pares usando una lambda como argumento
List<int> pares = numeros.FindAll(n => n % 2 == 0);
// pares contiene: 2, 4, 6, 8, 10

En este ejemplo, pasamos la lambda n => n % 2 == 0 como argumento al método FindAll, que filtra la lista según el predicado proporcionado.

Uso con LINQ

LINQ hace un uso extensivo de las expresiones lambda para definir operaciones sobre colecciones:

var numeros = new[] { 1, 2, 3, 4, 5 };

// Usar lambda con el método Where para filtrar
var mayoresQueTres = numeros.Where(n => n > 3);
// mayoresQueTres contiene: 4, 5

// Usar lambda con Select para transformar elementos
var cuadrados = numeros.Select(n => n * n);
// cuadrados contiene: 1, 4, 9, 16, 25

Aquí, las lambdas definen qué elementos filtrar y cómo transformarlos.

Ordenamiento personalizado

Las lambdas son ideales para definir criterios de ordenamiento personalizados:

List<string> nombres = new List<string> { "Ana", "Carlos", "Beatriz", "David" };

// Ordenar por longitud del nombre usando una lambda
nombres.Sort((a, b) => a.Length.CompareTo(b.Length));
// nombres ahora contiene: "Ana", "David", "Carlos", "Beatriz"

En este caso, la lambda define cómo comparar dos elementos para determinar su orden.

Eventos y callbacks

Las lambdas también son útiles para manejar eventos o definir callbacks:

Button boton = new Button();

// Asignar un manejador de eventos usando una lambda
boton.Click += (sender, e) => {
    Console.WriteLine("¡Botón pulsado!");
};

Esta lambda se ejecutará cada vez que ocurra el evento Click del botón.

Métodos de acción asíncrona

En programación asíncrona, las lambdas permiten definir qué hacer cuando una tarea se completa:

Task.Run(() => {
    // Código que se ejecuta en segundo plano
    Console.WriteLine("Procesando en segundo plano...");
})
.ContinueWith(task => {
    // Código que se ejecuta cuando la tarea anterior termina
    Console.WriteLine("Procesamiento completado");
});

Delegados predefinidos

C# incluye varios tipos de delegados predefinidos que facilitan el uso de lambdas como argumentos:

// Action - para lambdas que no devuelven valor
Action<string> mostrarMensaje = mensaje => Console.WriteLine(mensaje);
mostrarMensaje("Hola mundo");

// Predicate - para lambdas que devuelven un booleano
Predicate<int> esMayorDeEdad = edad => edad >= 18;
bool adulto = esMayorDeEdad(20); // true

// Comparison - para lambdas que comparan dos valores
Comparison<string> compararLongitud = (s1, s2) => s1.Length.CompareTo(s2.Length);
string[] palabras = { "corto", "larguísimo", "medio" };
Array.Sort(palabras, compararLongitud);
// palabras contiene: "corto", "medio", "larguísimo"

Métodos de extensión personalizados

Podemos crear nuestros propios métodos de extensión que acepten lambdas como argumentos:

public static class ExtensionesEnteros
{
    public static int Procesar(this int numero, Func<int, int> procesador)
    {
        return procesador(numero);
    }
}

// Uso:
int resultado = 5.Procesar(n => n * n + 2);
// resultado = 27 (5² + 2)

Ventajas de usar lambdas como argumentos

El uso de lambdas como argumentos ofrece varias ventajas:

  • Concisión: Evita tener que definir métodos separados para operaciones simples.
  • Claridad: El código es más legible al definir la operación justo donde se usa.
  • Contexto local: Las lambdas pueden acceder a variables del ámbito donde se definen.
  • Flexibilidad: Permiten personalizar el comportamiento de métodos genéricos.

Las expresiones lambda como argumentos son una herramienta fundamental en C# moderno, especialmente cuando se trabaja con colecciones, LINQ, eventos y programación asíncrona. Dominando esta técnica, podrás escribir código más elegante, conciso y expresivo.

Aprende CSharp online

Otros ejercicios de programación de CSharp

Evalúa tus conocimientos de esta lección Lambdas 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 de las expresiones lambda en C#.
  • Aprender a definir lambdas con diferentes números de parámetros y bloques de código.
  • Entender la inferencia de tipos y la captura de variables en lambdas.
  • Conocer cómo utilizar lambdas como argumentos en métodos, especialmente en colecciones y LINQ.
  • Identificar las ventajas y aplicaciones prácticas de las lambdas en programación moderna en C#.