Domknięcia i przechwytywane zmienne
Zobacz, jak funkcje lokalne przechwytują stan.
Domknięcia i przechwytywane zmienne to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.
Domknięcia przechwytujące stan lokalny
Funkcja lokalna (lub lambda) może odczytywać i modyfikować zmienne z otaczającej metody. Nazywa się to przechwytywaniem, a funkcja wraz z przechwyconymi zmiennymi tworzy domknięcie.
Przechwytywanie zmiennej
Funkcja lokalna korzysta bezpośrednio ze zmiennej factor z otaczającej metody. Nie otrzymuje jej jako parametru, lecz przechwytuje ją z otaczającego zakresu.
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));
}
}Przechwycone zmienne są żywymi odwołaniami
Domknięcie przechwytuje zmienną, a nie migawkę jej wartości. Jeśli zmienna zmieni się po zdefiniowaniu funkcji, funkcja zobaczy nową wartość.
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
}
}Modyfikowanie przechwyconych zmiennych
Domknięcie może zapisywać do przechwyconej zmiennej, a zmiana jest również widoczna w otaczającej metodzie. Dzięki temu domknięcia dobrze nadają się do gromadzenia stanu.
using System;
public class Program
{
public static void Main()
{
int count = 0;
void Tick() => count++;
Tick(); Tick(); Tick();
Console.WriteLine(count); // 3
}
}Zwracanie domknięcia
Gdy zwracana lambda przechwytuje zmienne lokalne, zmienne te żyją dłużej niż metoda. Przechwycony stan istnieje tak długo, jak długo istnieje delegat.
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());
}
}Niezależne domknięcia
Każde wywołanie fabryki tworzy nowy zestaw przechwyconych zmiennych. Dwa utworzone w ten sposób liczniki nie wpływają na siebie.
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
}
}Poprawka dotycząca przechwytywania w foreach
We współczesnym języku C# zmienna pętli foreach jest tworzona na nowo w każdej iteracji, dlatego domknięcia przechwytują oczekiwaną wartość. Każda z poniższych lambd zapamiętuje własny element.
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
}
}Przechwytywanie w pętli for
Klasyczna pułapka polega na tym, że jedna zmienna pętli for jest współdzielona między iteracjami, więc wszystkie domknięcia widzą jej końcową wartość. Aby przechwycić różne wartości, należy skopiować ją do zmiennej lokalnej tworzonej w każdej iteracji.
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
}
}Domknięcia przechwytują przez odwołanie, nie przez wartość
Ponieważ przechwytywanie odbywa się przez odwołanie, domknięcie zauważy modyfikację oryginalnej zmiennej po jej przechwyceniu. Należy o tym pamiętać, gdy znaczenie ma moment odczytu i zapisu.
using System;
public class Program
{
public static void Main()
{
string message = "first";
Action print = () => Console.WriteLine(message);
print(); // first
message = "second";
print(); // second
}
}Praktyczne zastosowanie: konfigurowalne zachowanie
Domknięcia pozwalają tworzyć małe funkcje wstępnie wyposażone w kontekst. W tym przykładzie funkcja rabatowa przechwytuje stawkę, tworząc wielokrotnego użytku skonfigurowany kalkulator.
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));
}
}Spróbuj samodzielnie
Utwórz fabrykę liczników, której zwracane domknięcie zachowuje prywatny stan, a następnie utwórz za jej pomocą dwa niezależne liczniki.
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
}
}Szybkie sprawdzenie
Przeanalizuj sposób działania przechwytywania.
Podsumowanie
Domknięcia przechwytują zmienne z otaczającego zakresu przez odwołanie.
- Funkcja widzi bieżącą wartość zmiennej, w tym zmiany wprowadzone później.
- Może modyfikować przechwycone zmienne, współdzieląc stan z metodą.
- Zwrócone domknięcia utrzymują przy życiu przechwycone zmienne.
- W pętli
fornależy używać zmiennej lokalnej tworzonej w każdej iteracji, aby przechwytywać różne wartości.
Ucz się C# dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 93
- Lekcje
- 346
Często zadawane pytania
Czy lekcja „Domknięcia i przechwytywane zmienne” jest bezpłatna?
Tak — pełny tekst „Domknięcia i przechwytywane zmienne” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Domknięcia i przechwytywane zmienne”?
Zobacz, jak funkcje lokalne przechwytują stan. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć C# Academy?
Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Domknięcia i przechwytywane zmienne”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?
Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Deklarowanie funkcji lokalnych
- Domknięcia i przechwytywane zmienne
- Statyczne funkcje lokalne
- Funkcje lokalne a lambdy