CodeGym /Cursos /C# SELF /Captura de variables por funciones locales

Captura de variables por funciones locales

C# SELF
Nivel 11 , Lección 5
Disponible

1. Introducción

Recordando el ámbito

Imagina que las variables son empleados de una gran oficina, y los métodos, bucles y bloques de código son habitaciones y despachos. A algunos empleados solo se les deja entrar en su propia habitación, y a otros en todo el edificio. Dónde puede estar cada uno — eso es su ámbito (scope).

El ámbito determina dónde una variable declarada es “visible” en el programa y dónde se puede usar.

Tipos principales de ámbitos

En C# se pueden distinguir estos ámbitos principales:

Ámbito Ejemplo Dónde es "visible" la variable
Local Dentro de un método o bloque Solo dentro de ese bloque
Parámetro de método En la signatura del método Solo dentro del método
Variable de clase (campo) En el cuerpo de la clase fuera de los métodos En todos los métodos de esa clase
Variable dentro de un bucle/condición Dentro de
{}
de un bucle/if
Solo dentro de esos
{}

Ejemplo con explicaciones

public class Office
{
    
  
int buildingNumber = 50; // Campo de clase: visible en todos los métodos public void PrintInfo() {
int roomNumber = 101; // Variable local: visible solo dentro de PrintInfo if (roomNumber > 100) {
int deskNumber = 5; // Visible solo dentro de este bloque if Console.WriteLine(deskNumber);
} Console.WriteLine(deskNumber); // ¡Error! deskNumber ya no es visible aquí
}
}

2. Funciones locales y ámbito

¿Quién ve a quién?

Cuando declaras una función local dentro de un método (o incluso dentro de un bucle o condición), está en el mismo ámbito que las variables declaradas arriba. Una función local es como “parte de ese mismo despacho”.

Ejemplo

La función local ve las variables del ámbito que la rodea


    void PrintWithPrefix(string mensaje)
{
    
  
string prefijo = "[LOG]: "; void Print() {
Console.WriteLine( prefijo + mensaje); // ¡ve ambas variables!
} Print();
}

Aquí las variables prefijo y mensaje son visibles dentro de la función local Print, porque están declaradas en el mismo o en un ámbito más amplio.

¿Cuántos ámbitos hay aquí?

En el ejemplo de arriba:

  • hay el ámbito del método PrintWithPrefix
  • dentro de él — el ámbito de la función Print
Las funciones locales no crean su propia “habitación” completamente: pueden ver todo lo que hay en el pasillo (el método).

3. Captura de variables (Capture)

Captura de variables — es cuando una función local usa variables que fueron declaradas fuera de esa función, pero en el mismo ámbito.

Las funciones locales y los métodos anónimos (expresiones lambda, ya llegaremos a eso) recuerdan (o “capturan”) todas las variables que tenían disponibles al declararse.

Se puede decir que las funciones hacen como una foto (capture) del mundo que las rodea — y pueden usar esas variables incluso cuando se llaman mucho después.

Esquemáticamente

Método Main
└─ variable x
└─ función local F() ← "captura" x

Ejemplo — captura más simple

void CounterExample()
{
    int contador = 0;

    void Increase()
    {
        contador++; // Esta función captura la variable contador
    }

    Increase();
    Increase();
    Console.WriteLine(contador); // Mostrará 2
}
La función local captura una variable del ámbito externo

Aquí, después de dos llamadas a la función local Increase, el valor de contador sube a 2.

4. Uso de la captura de variables

La captura de variables permite “pasar” datos entre el ámbito del método y las funciones locales de forma cómoda, sin tener que usar parámetros extra.

Si no existiera la captura, tendrías que pasar todas las variables como parámetros:

void CounterExampleWithoutCapture()
{
    int contador = 0;

    void Increase(ref int c)
    {
        c++;
    }

    Increase(ref contador);
    Increase(ref contador);
    Console.WriteLine(contador);
}

Eso es incómodo — ¿para qué estar escribiendo ref y estropear la signatura de la función, si puede “ver” fácilmente las variables de fuera?

5. Funciones locales y vida de las variables después de salir del método

¿Las variables viven más que el método?

Si pasas una función local (o un delegado con lambda) fuera del método actual, las variables capturadas automáticamente dejan de “morir” al salir del método. El CLR (máquina virtual .NET) se encarga — todo lo necesario se “mantiene agarrado” en memoria.

Ejemplo: funciones viven fuera del método

Func<int> GetCounter()
{
    int cuenta = 0;
    int Increment()
    {
        cuenta++;
        return cuenta;
    }
    return Increment; // ¡Devolvemos la función hacia fuera!
}

var contador = GetCounter();
Console.WriteLine(contador()); // 1
Console.WriteLine(contador()); // 2
Closure: la variable cuenta vive después de salir del método

Aquí, incluso después de que termine el método GetCounter, la variable cuenta sigue viva, porque la función devuelta la capturó. Esto se llama closure (cierre) — ya hablaremos de esto en otra lección, pero a nivel de funciones locales el mecanismo es igual.

6. Errores típicos y escenarios curiosos

Reescribir la variable antes de llamar a la función local

A veces puede pasar que la variable que captura la función local se cambia antes de llamarla — y entonces el resultado puede ser diferente al esperado.

Ejemplo:


void Example()
{
    int x = 42;
    void PrintX() {  Console.WriteLine(x);  } 

    x = 100; // ¡La variable ha cambiado!
    PrintX(); // ¡Mostrará 100, no 42!
}

Truco: La función local siempre ve el valor más reciente de la variable en el momento de la llamada.

Captura de variables en bucles for/foreach (otra vez)

El clásico dolor: si estás escribiendo lógica en una entrevista o en un proyecto grande, revisa siempre: ¿no estaré capturando una variable “viva” del bucle, y cómo se va a comportar?

1
Cuestionario/control
Tuplas y funciones locales, nivel 11, lección 5
No disponible
Tuplas y funciones locales
Ventajas de las tuplas frente a out y tipos anónimos
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION