0Pricing
C# Academy · Lección

Clausuras y variables capturadas

Observe cómo las funciones locales capturan el estado.

Clausuras y variables capturadas es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.

Clausuras sobre el estado local

Una función local (o lambda) puede leer y modificar variables del método que la contiene. Esto se denomina captura, y la función junto con las variables que captura forman una clausura.

Capturar una variable

La función local utiliza directamente factor del método que la contiene. No lo recibe como parámetro, sino que lo captura del ámbito circundante.

using System;

public class Program
{
    public static void Main()
    {
        int factor = 3;
        int Scale(int n) => n * factor; // captures factor

        Console.WriteLine(Scale(5));
        Console.WriteLine(Scale(10));
    }
}

Las variables capturadas son referencias vivas

Una clausura captura la variable, no una instantánea de su valor. Si la variable cambia después de definir la función, la función ve el nuevo valor.

using System;

public class Program
{
    public static void Main()
    {
        int offset = 10;
        int Add(int n) => n + offset;

        Console.WriteLine(Add(1)); // 11
        offset = 100;
        Console.WriteLine(Add(1)); // 101 - sees updated offset
    }
}

Modificar variables capturadas

Una clausura puede escribir en una variable capturada, y el cambio también es visible en el método que la contiene. Esto hace que las clausuras sean útiles para acumular estado.

using System;

public class Program
{
    public static void Main()
    {
        int count = 0;
        void Tick() => count++;

        Tick(); Tick(); Tick();
        Console.WriteLine(count); // 3
    }
}

Devolver una clausura

Cuando devuelve una lambda que ha capturado variables locales, esas variables sobreviven al método. El estado capturado vive tanto como el delegado.

using System;

public class Program
{
    static Func<int> MakeCounter()
    {
        int count = 0;
        return () => ++count; // captures count
    }

    public static void Main()
    {
        var next = MakeCounter();
        Console.WriteLine(next());
        Console.WriteLine(next());
        Console.WriteLine(next());
    }
}

Clausuras independientes

Cada llamada a una factoría crea un conjunto nuevo de variables capturadas. Dos contadores creados de esta forma no interfieren entre sí.

using System;

public class Program
{
    static Func<int> MakeCounter()
    {
        int count = 0;
        return () => ++count;
    }

    public static void Main()
    {
        var a = MakeCounter();
        var b = MakeCounter();
        Console.WriteLine(a()); // 1
        Console.WriteLine(a()); // 2
        Console.WriteLine(b()); // 1 - separate state
    }
}

La corrección de captura de foreach

En el C# moderno, la variable del bucle foreach es nueva en cada iteración, por lo que las clausuras capturan el valor esperado. Cada lambda siguiente recuerda su propio elemento.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var actions = new List<Action>();
        foreach (var i in new[] { 1, 2, 3 })
            actions.Add(() => Console.WriteLine(i));

        foreach (var act in actions) act(); // prints 1, 2, 3
    }
}

Capturar en un bucle for

Un error clásico: una sola variable del bucle for se comparte entre las iteraciones, por lo que todas las clausuras ven su valor final. Copie la variable en una local por iteración para capturar valores distintos.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var actions = new List<Action>();
        for (int i = 0; i < 3; i++)
        {
            int copy = i; // fresh local each iteration
            actions.Add(() => Console.WriteLine(copy));
        }
        foreach (var act in actions) act(); // prints 0, 1, 2
    }
}

Las clausuras capturan por referencia, no por valor

Como la captura se realiza por referencia, la clausura observa cualquier modificación del original posterior a la captura. Téngalo presente cuando sea importante el momento en que se realizan las lecturas y escrituras.

using System;

public class Program
{
    public static void Main()
    {
        string message = "first";
        Action print = () => Console.WriteLine(message);

        print();          // first
        message = "second";
        print();          // second
    }
}

Uso práctico: comportamiento configurable

Las clausuras permiten crear funciones pequeñas precargadas con contexto. Aquí, una función de descuento captura una tasa y produce una calculadora reutilizable y configurada.

using System;

public class Program
{
    static Func<double, double> MakeDiscount(double rate)
        => price => price * (1 - rate);

    public static void Main()
    {
        var tenOff = MakeDiscount(0.10);
        var halfOff = MakeDiscount(0.50);
        Console.WriteLine(tenOff(100));
        Console.WriteLine(halfOff(100));
    }
}

Pruébelo usted mismo

Cree una factoría de contadores cuya clausura devuelta mantenga vivo el estado privado y, después, cree dos contadores independientes a partir de ella.

using System;

public class Program
{
    static Func<int> MakeStepper(int step)
    {
        int current = 0;
        return () => { current += step; return current; }; // captures current and step
    }

    public static void Main()
    {
        var byTwos = MakeStepper(2);
        var byTens = MakeStepper(10);
        Console.WriteLine(byTwos()); // 2
        Console.WriteLine(byTwos()); // 4
        Console.WriteLine(byTens()); // 10 - separate state
    }
}

Comprobación rápida

Razonar sobre cómo funciona la captura.

Recapitulación

Las clausuras capturan por referencia las variables del ámbito contenedor.

  • La función ve el valor actual de la variable, incluidos los cambios posteriores.
  • Puede modificar las variables capturadas y compartir estado con el método.
  • Las clausuras devueltas mantienen vivas sus variables capturadas.
  • Use una variable local por iteración en un bucle for para capturar valores distintos.

Preguntas frecuentes

¿La lección «Clausuras y variables capturadas» es gratis?

Sí — el texto completo de «Clausuras y variables capturadas» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Clausuras y variables capturadas»?

Observe cómo las funciones locales capturan el estado. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «Clausuras y variables capturadas»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Declaración de funciones locales
  2. Clausuras y variables capturadas
  3. Funciones locales estáticas
  4. Funciones locales frente a lambdas
← Volver a C# Academy