Debugowanie w C# — breakpointy i watch

Zamiast teorii — konkretny błąd i konkretne narzędzia Visual Studio, które pomogą go znaleźć.
Błąd, który znajdziemy
static double ObliczSrednia(List<int> oceny)
{
int suma = 0;
for (int i = 0; i <= oceny.Count; i++) // błąd: <= zamiast <
{
suma += oceny[i];
}
return suma / oceny.Count;
}Wywołanie ObliczSrednia(new List<int> { 5, 4, 3 }) rzuci IndexOutOfRangeException. Zamiast zgadywać, gdzie jest problem, przejdźmy przez proces debugowania krok po kroku.
Breakpoint — F9
Kliknij na lewym marginesie linijki suma += oceny[i]; (albo ustaw kursor na tej linii i naciśnij F9) — pojawi się czerwona kropka. Uruchom program w trybie debugowania (F5). Program zatrzyma się na tej linii, zanim się wykona, dając Ci pełny podgląd stanu programu w tym dokładnym momencie.
Step Over, Step Into, Step Out
Trzy podstawowe klawisze do poruszania się po zatrzymanym programie:
- F10 (Step Over) — wykonaj bieżącą linię i przejdź do następnej, nie wchodząc do wywoływanych metod. Używaj, gdy ufasz, że dana metoda działa poprawnie.
- F11 (Step Into) — wykonaj bieżącą linię, ale jeśli wywołuje metodę, wejdź do jej wnętrza. Używaj, gdy podejrzewasz błąd wewnątrz tej metody.
- Shift+F11 (Step Out) — dokończ wykonanie bieżącej metody i wróć do miejsca, skąd została wywołana. Używaj, gdy wszedłeś za głęboko i chcesz wrócić wyżej.
W naszym przykładzie naciskaj F10 kilka razy, obserwując wartość i — zobaczysz, że pętla próbuje wykonać się dla i == oceny.Count (czyli 3), a oceny[3] nie istnieje w liście trzyelementowej (indeksy 0, 1, 2).
Watch, Locals, Autos — podgląd zmiennych na żywo
Gdy program jest zatrzymany na breakpoincie, w dolnym panelu Visual Studio masz trzy okna:
- Locals — automatycznie pokazuje wszystkie zmienne lokalne w bieżącym zasięgu (tutaj:
oceny,suma,i). - Watch — dodajesz konkretne wyrażenie ręcznie (np.
oceny.Countalbooceny[i]), żeby śledzić je przez cały czas debugowania, nawet gdy zmienia się kontekst. - Autos — pokazuje zmienne użyte w bieżącej i poprzedniej linii — dobre do szybkiego podglądu bez ręcznego dodawania.
Dodaj oceny.Count i i do Watch — zobaczysz w czasie rzeczywistym, że i dochodzi do 3, podczas gdy oceny.Count wynosi 3 — a warunek pętli i <= oceny.Count pozwala i osiągnąć wartość równą długości listy, co jest o jeden za dużo.
Warunkowy breakpoint — zatrzymaj się tylko wtedy, gdy to ma sens
Dla pętli wykonującej się setki razy, ręczne klikanie F10 aż do interesującego Cię przypadku jest stratą czasu. Kliknij prawym przyciskiem na breakpoint → Warunki (Conditions) → wpisz np. i == 3. Program zatrzyma się tylko wtedy, gdy i osiągnie tę wartość — pomijając wszystkie wcześniejsze, poprawne iteracje.
Break on exception — łap wyjątek w miejscu, gdzie faktycznie powstaje
Domyślnie program zatrzymuje się dopiero tam, gdzie wyjątek jest obsłużony (albo w ogóle się wywala, jeśli nikt go nie obsłużył) — niekoniecznie tam, gdzie powstał. W menu Debug → Windows → Exception Settings (albo Ctrl+Alt+E) zaznacz Common Language Runtime Exceptions. Teraz Visual Studio zatrzyma program dokładnie w linii suma += oceny[i];, w momencie rzucenia wyjątku — zamiast gdzieś dalej w stosie wywołań, gdzie kontekst oryginalnego błędu już częściowo zniknął.
Call Stack — jak tu trafiłeś
Okno Call Stack pokazuje pełną ścieżkę wywołań, które doprowadziły do bieżącej linii — który kod wywołał ObliczSrednia, a ten z kolei co wywołał wcześniej. Dla błędów głęboko zagnieżdżonych w wielowarstwowej aplikacji to często szybszy sposób zrozumienia kontekstu niż przechodzenie krok po kroku od samego początku programu.
Poprawka
static double ObliczSrednia(List<int> oceny)
{
int suma = 0;
for (int i = 0; i < oceny.Count; i++) // poprawione: < zamiast <=
{
suma += oceny[i];
}
return suma / (double)oceny.Count; // dodatkowo: rzutowanie na double, żeby uniknąć dzielenia całkowitoliczbowego
}Dwa błędy w jednej metodzie: <= zamiast < (błąd o jeden za dużo) oraz dzielenie całkowitoliczbowe (suma / oceny.Count obcięłoby wynik do liczby całkowitej, np. 4/3 = 1 zamiast 1.33) — oba wykryte tym samym procesem: breakpoint, obserwacja zmiennych, zrozumienie dlaczego wartość jest inna niż oczekiwana.
Kiedy debugger nie wystarczy — logowanie
Dla błędów, które pojawiają się tylko w produkcji (nie da się podłączyć debuggera na żywo do serwera klienta), albo dla błędów zależnych od czasu (race conditions, gdzie zatrzymanie programu na breakpoincie zmienia jego zachowanie), jedynym praktycznym narzędziem pozostaje logowanie — Debug.WriteLine podczas developmentu, a w produkcji ustrukturyzowane logi (Serilog, ILogger). Debugger i logi to nie konkurencyjne narzędzia — pierwszy jest lepszy do “namierz błąd na własnej maszynie teraz”, drugi do “zrozum, co się stało w systemie, którego nie masz przed sobą”.
Podsumowanie
Debugowanie w Visual Studio to konkretny zestaw narzędzi, nie intuicja: breakpoint (F9) zatrzymuje program w wybranym miejscu, F10/F11/Shift+F11 pozwalają poruszać się po kodzie z kontrolą nad tym, czy wchodzisz do wywoływanych metod, okna Watch/Locals/Autos pokazują wartości zmiennych na żywo, warunkowy breakpoint oszczędza czas przy pętlach i wielokrotnych wywołaniach, a Exception Settings łapie wyjątek dokładnie tam, gdzie powstaje, zamiast tam, gdzie został obsłużony. Ten sam zestaw kroków — ustaw breakpoint, obserwuj zmienne, zawężaj obszar — działa niezależnie od tego, czy błąd jest banalny, czy ukryty głęboko w wielowarstwowej aplikacji.
Powiązane: podstawy stojące za błędami poznasz w obsłudze błędów w C# i wpisie o NullReferenceException. Na produkcji zamiast debuggera masz logi (ILogger, Serilog).
🚀 Co dalej?
Zobacz to w praktyce na wideo i pobierz darmową roadmapę, żeby ułożyć naukę w spójną ścieżkę do pierwszej pracy.
- 🗺️ Pobierz darmową roadmapę Junior .NET Developer — 12 kroków od podstaw C# do pierwszej pracy: dev-hobby.pl
- 🎬 Subskrybuj kanał YouTube — nowe filmy co tydzień.
Zamień wiedzę w umiejętności
Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.
Pobieram roadmapę →
2 comments