Udostępnij za pośrednictwem


Debugowanie dla całkowitych początkujących

Niezmiennie, kod, który piszemy jako programiści, nie zawsze działa tak, jak się spodziewaliśmy. Czasami robi to coś zupełnie innego! Gdy wystąpi nieoczekiwana sytuacja, następnym zadaniem jest ustalenie, dlaczego i chociaż możemy być kuszeni, aby po prostu nadal wpatrować się w nasz kod przez wiele godzin, łatwiej i wydajniej używać narzędzia debugowania lub debugera.

Debuger, niestety, nie jest czymś, co może magicznie ujawnić wszystkie problemy lub "błędy" w naszym kodzie. Debugowanie oznacza uruchamianie kodu krok po kroku w narzędziu debugowania, takiego jak Visual Studio, aby znaleźć dokładny punkt, w którym wystąpił błąd programowania. Następnie rozumiesz, jakie poprawki należy wprowadzić w kodzie i narzędziach do debugowania, często umożliwiają wprowadzanie tymczasowych zmian, dzięki czemu można kontynuować uruchamianie programu.

Efektywne korzystanie z debugera jest również umiejętnością, która zajmuje dużo czasu i praktykowania, ale ostatecznie jest podstawowym zadaniem dla każdego dewelopera oprogramowania. W tym artykule wprowadzimy podstawowe zasady debugowania i przedstawimy wskazówki, które pomogą Ci rozpocząć pracę.

Wyjaśnij problem, zadając sobie odpowiednie pytania

Pomaga to wyjaśnić problem napotkany przed podjęciem próby jego rozwiązania. Oczekujemy, że wystąpił już problem w kodzie. W przeciwnym razie nie będziesz tutaj próbował dowiedzieć się, jak go debugować! Przed rozpoczęciem debugowania upewnij się, że zidentyfikowano problem, który próbujesz rozwiązać:

  • Czego oczekiwaliśmy od kodu?

  • Co się stało zamiast tego?

    Jeśli wystąpi błąd (wyjątek) podczas uruchamiania aplikacji, może to być dobra rzecz! Wyjątek jest nieoczekiwanym zdarzeniem napotkanym podczas uruchamiania kodu, zazwyczaj błędem pewnego rodzaju. Narzędzie do debugowania może przejść do dokładnego miejsca w kodzie, w którym wystąpił wyjątek, i może pomóc w zbadaniu możliwych poprawek.

    Jeśli coś innego się stało, jaki jest objaw problemu? Czy już podejrzewasz, gdzie wystąpił ten problem w kodzie? Jeśli na przykład kod wyświetla jakiś tekst, ale tekst jest niepoprawny, wiesz, że dane są nieprawidłowe lub kod, który ustawił tekst wyświetlany, ma jakąś usterkę. Wykonując kroki kodu w debugerze, możesz zbadać każdą i każdą zmianę zmiennych, aby dowiedzieć się dokładnie, kiedy i jak są przypisywane nieprawidłowe wartości.

Sprawdzanie założeń

Zanim zbadasz usterkę lub błąd, pomyśl o założeniach, które sprawiły, że oczekiwano określonego wyniku. Ukryte lub nieznane założenia mogą utrudniać identyfikację problemu, nawet jeśli w debugerze patrzysz bezpośrednio na jego przyczynę. Może istnieć długa lista możliwych założeń! Oto kilka pytań, które należy zadać sobie w celu zakwestionowania założeń.

  • Czy używasz odpowiedniego interfejsu API (czyli odpowiedniego obiektu, funkcji, metody lub właściwości)? Używany interfejs API może nie robić tego, co myślisz. (Po przeanalizowaniu wywołania interfejsu API w debugerze naprawa może wymagać podróży do dokumentacji, aby ułatwić zidentyfikowanie poprawnego interfejsu API).

  • Czy używasz interfejsu API poprawnie? Być może użyto odpowiedniego interfejsu API, ale nie użyto go w odpowiedni sposób.

  • Czy kod zawiera jakieś literówki? Niektóre literówki, takie jak proste błędy pisowni nazwy zmiennej, mogą być trudne do wyświetlenia, zwłaszcza podczas pracy z językami, które nie wymagają zadeklarowania zmiennych przed ich użyciem.

  • Czy wprowadziliśmy zmianę w kodzie i przyjęto założenie, że nie ma to związku z widocznym problemem?

  • Czy oczekiwano, że obiekt lub zmienna będzie zawierać określoną wartość (lub określony typ wartości), która różni się od tego, co naprawdę się stało?

  • Czy znasz intencję kodu? Często trudniej jest debugować kod innej osoby. Jeśli nie jest to twój kod, może być konieczne poświęcanie czasu na naukę dokładnie tego, co robi kod, zanim będzie można go skutecznie debugować.

    Napiwek

    Podczas pisania kodu zacznij od małego i zacznij od kodu, który działa! (Dobry przykładowy kod jest tutaj przydatny). Czasami łatwiej jest naprawić duży lub skomplikowany zestaw kodu, zaczynając od małego fragmentu kodu, który demonstruje podstawowe zadanie, które próbujesz osiągnąć. Następnie można modyfikować lub dodawać kod przyrostowo, testując w każdym momencie pod kątem błędów.

Kwestiując założenia, możesz skrócić czas znajdowania problemu w kodzie. Możesz również skrócić czas potrzebny na rozwiązanie problemu.

Przejdź przez kod w trybie debugowania, aby dowiedzieć się, gdzie wystąpił problem

Podczas normalnego uruchamiania aplikacji są wyświetlane błędy i nieprawidłowe wyniki dopiero po uruchomieniu kodu. Program może również zakończyć się nieoczekiwanie bez informowania o tym, dlaczego.

Po uruchomieniu aplikacji w debugerze nazywanym również trybem debugowania debuger aktywnie monitoruje wszystko, co dzieje się podczas uruchamiania programu. Umożliwia również wstrzymanie aplikacji w dowolnym momencie w celu zbadania jej stanu, a następnie przejście przez wiersz kodu w celu obserwowania wszystkich szczegółów w ten sposób.

W programie Visual Studio wprowadzasz tryb debugowania przy użyciu F5 (lub polecenia menu Debuguj>Rozpocznij debugowanie, przycisku Rozpocznij debugowanie lub ikony przedstawiającej przycisk Rozpocznij debugowanie na pasku narzędzi debugowania). Jeśli wystąpią jakiekolwiek wyjątki, pomocnik wyjątków programu Visual Studio przeniesie Cię do dokładnego punktu, w którym wystąpił wyjątek i udostępnia inne przydatne informacje. Aby uzyskać więcej informacji na temat obsługi wyjątków w kodzie, zobacz Techniki i narzędzia debugowania.

Jeśli nie otrzymasz wyjątku, prawdopodobnie masz dobry pomysł, gdzie szukać problemu w kodzie. W tym kroku użyjesz punktów przerwania z debugerem, aby umożliwić sobie dokładniejszą analizę kodu. Punkty przerwania to najbardziej podstawowa i niezbędna funkcja niezawodnego debugowania. Punkt przerwania wskazuje, gdzie program Visual Studio powinien wstrzymać uruchomiony kod, aby przyjrzeć się wartościom zmiennych lub zachowaniu pamięci, sekwencji uruchamiania kodu.

W programie Visual Studio można szybko ustawić punkt przerwania, klikając lewy margines obok wiersza kodu. Możesz też umieścić kursor w wierszu i nacisnąć F9.

Aby ułatwić zilustrowanie tych pojęć, przeprowadzimy Cię przez przykładowy kod, który zawiera już kilka usterek. Używamy języka C#, ale funkcje debugowania mają zastosowanie do języków Visual Basic, C++, JavaScript, Python i innych obsługiwanych języków. Podano również przykładowy kod dla języka Visual Basic, ale zrzuty ekranu znajdują się w języku C#.

Tworzenie przykładowej aplikacji (z niektórymi usterkami)

Następnie utworzysz aplikację, która zawiera kilka usterek.

  1. Musisz mieć zainstalowany program Visual Studio, a zainstalowane obciążenie programowanie aplikacji klasycznych platformy .NET.

    Jeśli program Visual Studio nie został jeszcze zainstalowany, przejdź do strony Visual Studio do pobrania, aby ją zainstalować bezpłatnie.

    Jeśli musisz zainstalować moduł, ale masz już zainstalowany Visual Studio, wybierz Tools>Get Tools and Features. Zostanie uruchomiony Instalator programu Visual Studio. Wybierz obciążenie programowanie aplikacji klasycznych platformy .NET, a następnie wybierz pozycję Modyfikuj.

  2. Otwórz program Visual Studio.

    W oknie uruchamiania wybierz pozycję Utwórz nowy projekt. Wpisz konsolę w polu wyszukiwania, wybierz jako język C# lub Visual Basic, a następnie wybierz pozycję Aplikacja konsolowa dla .NET. Wybierz pozycję Dalej. Wpisz ConsoleApp_FirstApp jako nazwę projektu i wybierz pozycję Dalej.

    Jeśli używasz innej nazwy projektu, musisz zmodyfikować wartość przestrzeni nazw tak, aby odpowiadała nazwie projektu podczas kopiowania przykładowego kodu.

    Wybierz zalecaną strukturę docelową lub platformę .NET 8, a następnie wybierz pozycję Utwórz.

    Jeśli nie widzisz szablonu projektu Console App dla platformy .NET, przejdź do pozycji Narzędzia >Pobierz narzędzia i funkcje, co spowoduje otwarcie Instalatora programu Visual Studio. Wybierz obciążenie tworzenie aplikacji desktopowych .NET, a następnie wybierz Modyfikuj.

    Program Visual Studio tworzy projekt konsoli, który jest wyświetlany w eksploratorze rozwiązań w okienku po prawej stronie.

  3. W Program.cs (lub Program.vb) zastąp cały kod domyślny następującym kodem. (Najpierw wybierz odpowiednią kartę języka— C# lub Visual Basic).

    • C#
    • Visual Basic
    using System;
    using System.Collections.Generic;
    
    namespace ConsoleApp_FirstApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Welcome to Galaxy News!");
                IterateThroughList();
                Console.ReadKey();
            }
    
            private static void IterateThroughList()
            {
                var theGalaxies = new List<Galaxy>
            {
                new Galaxy() { Name="Tadpole", MegaLightYears=400, GalaxyType=new GType('S')},
                new Galaxy() { Name="Pinwheel", MegaLightYears=25, GalaxyType=new GType('S')},
                new Galaxy() { Name="Cartwheel", MegaLightYears=500, GalaxyType=new GType('L')},
                new Galaxy() { Name="Small Magellanic Cloud", MegaLightYears=.2, GalaxyType=new GType('I')},
                new Galaxy() { Name="Andromeda", MegaLightYears=3, GalaxyType=new GType('S')},
                new Galaxy() { Name="Maffei 1", MegaLightYears=11, GalaxyType=new GType('E')}
            };
    
                foreach (Galaxy theGalaxy in theGalaxies)
                {
                    Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
                }
    
                // Expected Output:
                //  Tadpole  400,  Spiral
                //  Pinwheel  25,  Spiral
                //  Cartwheel, 500,  Lenticular
                //  Small Magellanic Cloud .2,  Irregular
                //  Andromeda  3,  Spiral
                //  Maffei 1,  11,  Elliptical
            }
        }
    
        public class Galaxy
        {
            public string Name { get; set; }
    
            public double MegaLightYears { get; set; }
            public object GalaxyType { get; set; }
    
        }
    
        public class GType
        {
            public GType(char type)
            {
                switch(type)
                {
                    case 'S':
                        MyGType = Type.Spiral;
                        break;
                    case 'E':
                        MyGType = Type.Elliptical;
                        break;
                    case 'l':
                        MyGType = Type.Irregular;
                        break;
                    case 'L':
                        MyGType = Type.Lenticular;
                        break;
                    default:
                        break;
                }
            }
            public object MyGType { get; set; }
            private enum Type { Spiral, Elliptical, Irregular, Lenticular}
        }
    }
    

    Naszym zamiarem dla tego kodu jest wyświetlenie nazwy galaktyki, odległości do galaktyki i typu galaktyki na liście. Aby debugować, ważne jest zrozumienie intencji kodu. Oto format jednego wiersza z listy, który chcemy pokazać w danych wyjściowych:

    nazwa galaktyki, odległości, typ galaktyki.

Uruchamianie aplikacji

Naciśnij F5 lub przycisk Rozpocznij debugowanieIkona przedstawiający przycisk Rozpocznij debugowanie. na pasku narzędzi debugowania znajdującym się nad edytorem kodu.

Aplikacja startuje i nie wykazuje wyjątków pokazywanych przez debuger. Jednak dane wyjściowe widoczne w oknie konsoli nie są takie, jakich się spodziewasz. Oto oczekiwane dane wyjściowe:

Tadpole  400,  Spiral
Pinwheel  25,  Spiral
Cartwheel, 500,  Lenticular
Small Magellanic Cloud .2,  Irregular
Andromeda  3,  Spiral
Maffei 1,  Elliptical

Zamiast tego zobaczysz następujące dane wyjściowe:

Tadpole  400,  ConsoleApp_FirstApp.GType
Pinwheel  25,  ConsoleApp_FirstApp.GType
Cartwheel, 500,  ConsoleApp_FirstApp.GType
Small Magellanic Cloud .2,  ConsoleApp_FirstApp.GType
Andromeda  3,  ConsoleApp_FirstApp.GType
Maffei 1, 11,  ConsoleApp_FirstApp.GType

Patrząc na dane wyjściowe i nasz kod, wiemy, że GType jest nazwą klasy, która przechowuje typ galaktyki. Staramy się pokazać rzeczywisty typ galaktyki (taki jak "Spiral"), a nie nazwę klasy!

Debugowanie aplikacji

  1. Gdy aplikacja nadal działa, wstaw punkt przerwania.

    W pętli foreach kliknij prawym przyciskiem myszy obok metody Console.WriteLine, aby otworzyć menu kontekstowe, a następnie wybierz punkt przerwania>Wstaw punkt przerwania z rozwijanego menu.

    • C#
    • Visual Basic
    foreach (Galaxy theGalaxy in theGalaxies)
    {
        Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
    }
    

    Po ustawieniu punktu przerwania czerwona kropka pojawi się na lewym marginesie.

    Jak widzisz problem w danych wyjściowych, rozpoczniesz debugowanie, patrząc na powyższy kod, który ustawia dane wyjściowe w debugerze.

  2. Wybierz ikonę Restartpokazującą przycisk RestartApp na pasku narzędzi debugowania. przycisk na pasku narzędzi debugowania (Ctrl + Shift + F5).

    Aplikacja wstrzymuje się w ustawionym punkcie przerwania. Żółte wyróżnienie wskazuje, gdzie debuger jest wstrzymany (żółty wiersz kodu nie został jeszcze wykonany).

  3. Umieść kursor nad zmienną GalaxyType po prawej, a następnie rozwiń theGalaxy.GalaxyTypepo lewej stronie ikony klucza. Zobaczysz, że GalaxyType zawiera właściwość MyGType, a wartość właściwości jest ustawiona na wartość Spiral.

    Zrzut ekranu debugera programu Visual Studio z wierszem kodu w kolorze żółtym, a menu otwarte poniżej właściwości Galaxy GalaxyType.

    "Spiral" jest rzeczywiście prawidłową wartością, której oczekiwano wypisania w konsoli! Dlatego dobrym początkiem jest uzyskanie dostępu do wartości w tym kodzie podczas uruchamiania aplikacji. W tym scenariuszu używamy niepoprawnego interfejsu API. Sprawdźmy, czy możesz rozwiązać ten problem podczas uruchamiania kodu w debugerze.

  4. W tym samym kodzie, podczas debugowania, umieść kursor na końcu theGalaxy.GalaxyType i zmień go na theGalaxy.GalaxyType.MyGType. Mimo że można dokonać edycji, edytor kodu wyświetla błąd (czerwona falista linia). (W Visual Basic błąd nie jest wyświetlany, a ta sekcja kodu działa).

  5. Naciśnij F11 (Debugowanie>Krok do lub przycisk Przejdź do na pasku narzędzi debugowania), aby wykonać bieżący wiersz kodu.

    F11 przesuwa debuger (i wykonuje kod) o jedną instrukcję na raz. F10 (Step Over) jest podobnym poleceniem i oba są przydatne podczas nauki korzystania z debugera.

    Podczas próby kontynuowania pracy debugera zostanie wyświetlone okno dialogowe Hot Reload, co oznacza, że nie można skompilować edycji.

    Zrzut ekranu debugera programu Visual Studio z wierszem kodu wyróżnionym na czerwono i polem komunikatu z wybraną opcją Edytuj.

    Zostanie wyświetlone okno dialogowe Edytuj i Kontynuuj, wskazując, że nie można skompilować zmian.

    Zrzut ekranu debugera programu Visual Studio z wierszem kodu wyróżnionym na czerwono i polem komunikatu z wybraną opcją Edytuj.

    Notatka

    Aby debugować przykładowy kod języka Visual Basic, pomiń kilka następnych kroków do momentu kliknięcia ikony ponownego uruchamianiaz przyciskiem Uruchom ponownie aplikację na pasku narzędzi Debugowanie. przycisk.

  6. Wybierz pozycję Edytuj w polu komunikatu Przeładowywania na Gorąco lub Edytuj i Kontynuuj. Widzisz teraz komunikat o błędzie w oknie listy błędów . Błąd wskazuje, że 'object' nie zawiera definicji MyGType.

    Zrzut ekranu debugera programu Visual Studio z wierszem kodu wyróżnionym na czerwono i w oknie Lista błędów z dwoma wymienionymi błędami.

    Mimo że ustawiamy każdą galaktykę z obiektem typu GType (który ma właściwość MyGType), debuger nie rozpoznaje obiektu theGalaxy jako obiektu typu GType. Co się dzieje? Chcesz przejrzeć dowolny kod, który ustawia typ galaktyki. Kiedy to zrobisz, zobaczysz, że klasa GType na pewno ma właściwość MyGType, ale coś jest nie tak. Komunikat o błędzie dotyczący object okazuje się być wskazówką; w interpreterze języka typ wydaje się być obiektem typu object zamiast obiektu typu GType.

  7. Przeglądając kod związany z ustawieniem typu galaktyki, znajdujesz, że właściwość GalaxyType klasy Galaxy jest określona jako object zamiast GType.

    public object GalaxyType { get; set; }
    
  8. Zmień poprzedni kod w następujący sposób:

    public GType GalaxyType { get; set; }
    
  9. Wybierz ikonę Uruchom ponowniez przyciskiem do ponownego uruchomienia aplikacji na pasku narzędzi debugowania. przycisk na pasku narzędzi debugowania (Ctrl + Shift + F5) aby ponownie skompilować kod i uruchomić ponownie.

    Teraz, gdy debuger wstrzymuje się na Console.WriteLine, możesz zatrzymać wskaźnik myszy na theGalaxy.GalaxyType.MyGTypei zobaczyć, że wartość jest poprawnie ustawiona.

  10. Usuń punkt przerwania, klikając okrąg punktu przerwania na lewym marginesie (lub kliknij prawym przyciskiem myszy i wybierz punkt przerwania>Usuń punkt przerwania), a następnie naciśnij F5, aby kontynuować.

    Aplikacja jest uruchamiana i wyświetla dane wyjściowe. Wygląda dobrze, ale zauważasz jedną rzecz. Spodziewałeś się, że mała galaktyka Magellanic Cloud pojawi się jako nieregularna galaktyka w danych wyjściowych konsoli, ale w ogóle nie pokazuje typu galaktyki.

    Tadpole  400,  Spiral
    Pinwheel  25,  Spiral
    Cartwheel, 500,  Lenticular
    Small Magellanic Cloud .2,
    Andromeda  3,  Spiral
    Maffei 1,  Elliptical
    
  11. Ustaw punkt przerwania w tym wierszu kodu przed instrukcją switch (przed instrukcją Select w Visual Basic).

    • C#
    • Visual Basic
    public GType(char type)
    

    Ten fragment kodu to miejsce, gdzie ustawiany jest typ galaktyki, dlatego chcemy się temu dokładniej przyjrzeć.

  12. Wybierz ikonę Uruchom ponowniez przyciskiem Uruchom ponownie aplikację na pasku narzędzi Debugowanie. przycisk na pasku narzędzi debugowania (Ctrl + Shift + F5) w celu ponownego uruchomienia.

    Debuger wstrzymuje się w wierszu kodu, w którym ustawiono punkt przerwania.

  13. Umieść kursor nad zmienną type. Widzisz wartość S (po kodzie znaku). Interesuje Cię wartość I, jak wiesz, że jest to nieregularny typ galaktyki.

  14. Naciśnij F5 i ponownie umieść kursor na zmiennej type. Powtórz ten krok do momentu wyświetlenia wartości I w zmiennej type.

    Zrzut ekranu debugera programu Visual Studio z wierszem kodu w kolorze żółtym i oknem z wartością zmiennej typu 73 I.

  15. Teraz naciśnij F11 (Debugowanie>Krok do).

  16. Naciśnij F11, aż zatrzymasz się w wierszu kodu w instrukcji switch dla wartości "I" (instrukcjaSelect dla języka Visual Basic). W tym miejscu zobaczysz wyraźny problem wynikający z literówki. Oczekiwano, że kod przechodzi do miejsca, w którym ustawia MyGType jako typ galaktyki Nieregularny, ale debuger pomija ten kod całkowicie i wstrzymuje się w sekcji default instrukcji switch ( instrukcjaElse w Visual Basic).

    Zrzut ekranu przedstawiający błąd literówki.

    Patrząc na kod, zauważasz literówkę w instrukcji case 'l'. Powinna to być case 'I'.

  17. Wybierz kod dla case 'l' i zastąp go case 'I'.

  18. Usuń punkt przerwania, a następnie wybierz przycisk Uruchom ponownie, aby ponownie uruchomić aplikację.

    Usterki zostały naprawione teraz i zostaną wyświetlone oczekiwane dane wyjściowe.

    Naciśnij dowolny, aby zakończyć aplikację.

Streszczenie

Gdy wystąpi problem, użyj poleceń debugera i kroku , takich jak F10 i F11, aby znaleźć region kodu z problemem.

Notatka

Jeśli trudno jest zidentyfikować region kodu, w którym występuje problem, ustaw punkt przerwania w kodzie uruchamianym przed wystąpieniem problemu, a następnie użyj poleceń kroków do momentu wyświetlenia manifestu problemu. Możesz również użyć punktów śledzenia do rejestrowania komunikatów w oknie Output. Patrząc na zarejestrowane komunikaty (i zauważając, które komunikaty nie zostały jeszcze zarejestrowane!), często można odizolować region kodu z problemem. Może być konieczne powtórzenie tego procesu kilka razy, aby go zawęzić.

Jeśli znajdziesz region kodu z problemem, użyj debugera do zbadania. Aby znaleźć przyczynę problemu, sprawdź kod problemu podczas uruchamiania aplikacji w debugerze:

  • Sprawdź zmienne i sprawdź, czy zawierają one typ wartości, które powinny zawierać. Jeśli znajdziesz złą wartość, sprawdź, gdzie ustawiono nieprawidłową wartość (aby znaleźć, gdzie ustawiono wartość, może być konieczne ponowne uruchomienie debugera, sprawdź stos wywołań lub oba).

  • Sprawdź, czy aplikacja wykonuje oczekiwany kod. (Na przykład w przykładowej aplikacji spodziewaliśmy się, że kod instrukcji switch ustawi typ galaktyki na Nieregularny, ale aplikacja pominąła kod ze względu na literówkę).

Napiwek

Używasz debuggera, aby pomóc sobie w znajdowaniu usterek. Narzędzie do debugowania może znaleźć błędy dla Ciebie tylko wtedy, gdy zna intencję kodu. Narzędzie może znać intencję kodu tylko wtedy, gdy deweloper wyrazi ten zamiar. Pisanie testów jednostkowych jest tym, jak to zrobić.

Następne kroki

W tym artykule przedstawiono kilka ogólnych pojęć dotyczących debugowania. Następnie możesz dowiedzieć się więcej na temat debugera.