Udostępnij za pomocą


Debugowanie dla całkowitych początkujących

Choć zawsze się tego spodziewamy, kod, który piszemy jako programiści, nie zawsze działa, tak jak oczekiwaliś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, w celu znalezienia dokładnego punktu, 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ą przeszkadzać w zidentyfikowaniu problemu, nawet jeśli patrzysz bezpośrednio na jego przyczynę w debugerze. 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ć.

    Wskazówka

    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 krok po kroku przechodzenie przez kod, aby obserwować każdy szczegół, jak się dzieje.

W programie Visual Studio wprowadzasz tryb debugowania przy użyciu F5 (lub polecenia menu Debuguj>Rozpocznij debugowanie lub przycisku o nazwie Rozpocznij debugowaniez przyciskiem 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żywasz punktów przerwania przy pomocy debugera, aby dać sobie szansę na 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 i pakiet roboczy rozwój aplikacji dla komputerów stacjonarnych .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ć obciążenie, ale masz już program Visual Studio, wybierz pozycję Narzędzia>Pobierz narzędzia i funkcje. Zostanie uruchomiony Instalator programu Visual Studio. Wybierz obciążenie programowanie aplikacji .NET na komputerach stacjonarnych, a następnie wybierz Modyfikuj.

  2. Otwórz program Visual Studio.

    W oknie uruchamiania wybierz pozycję Utwórz nowy projekt. Wpisz konsolę w polu wyszukiwania, wybierz język C# lub Visual Basic jako język, a następnie wybierz pozycję Aplikacja konsolowa dla platformy .NET. Wybierz Dalej. Wpisz ConsoleApp_FirstApp jako nazwę projektu i wybierz przycisk 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 programowanie aplikacji .NET na komputerach stacjonarnych, 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 poniższym kodem. (Najpierw wybierz odpowiednią kartę języka— C# lub 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ść, typ galaktyki.

Uruchom aplikację

Naciśnij F5 lub Icon showing Start Debugging button. na pasku narzędzi debugowania, znajdującym się nad edytorem kodu.

Aplikacja się uruchamia i debuger nie pokazuje żadnych wyjątków. Jednak dane wyjściowe widoczne w oknie konsoli nie są tym, czego 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 to nazwa 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.

    foreach W pętli kliknij prawym przyciskiem myszy obok metody Console.WriteLine, aby wyświetlić menu kontekstowe, a następnie wybierz pozycję Punkt przerwania> z wysuwanego menu Wstaw punkt przerwania.

    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 przycisk Uruchom ponowniez ikoną RestartApp 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. Najedź kursorem na zmienną GalaxyType po prawej stronie, a następnie rozwiń theGalaxy.GalaxyType po lewej stronie ikony klucza. Zobaczysz, że GalaxyType zawiera właściwość MyGType, a wartość właściwości jest ustawiona na Spiral.

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

    "Spiral" jest rzeczywiście prawidłową wartością, której oczekiwano, że zostanie wyświetlona 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 (Debuguj> lub Przejdź do) na pasku narzędzi debugowania, aby wykonać bieżący wiersz kodu.

    F11 przesuwa debuger do przodu (i wykonuje kod) jedna instrukcja na raz. F10 (Step Over) jest podobnym poleceniem i oba są przydatne podczas uczenia się, jak używać debugera.

    Podczas próby kontynuowania działania debugera zostanie wyświetlone okno dialogowe Hot Reload, co wskazuje, że nie można skompilować wprowadzonych zmian.

    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 Edytowanie i kontynuowanie, które informuje, że edycje nie mogą zostać skompilowane.

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

    Uwaga / Notatka

    Aby debugować przykładowy kod języka Visual Basic, pomiń kilka następnych kroków, dopóki nie zostanie wyświetlony monit o kliknięcie ikony ponownego uruchomieniaz przyciskiem Uruchom aplikację na pasku narzędzi Debugowanie.

  6. Wybierz pozycję Edytuj w polu komunikatu Przeładuj ponownie lub Edytuj i kontynuuj . W oknie Lista błędów zostanie wyświetlony komunikat o błędzie . Błąd wskazuje, że element 'object' nie zawiera definicji elementu MyGType.

    Zrzut ekranu przedstawiający debuger 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 MyGType właściwość), debuger nie rozpoznaje theGalaxy obiektu jako obiektu typu GType. Co się dzieje? Chcesz przejrzeć dowolny kod, który ustawia typ galaktyki. Gdy to zrobisz, zobaczysz, że GType klasa na pewno ma właściwość MyGType, ale coś nie jest w porządku. Komunikat o błędzie object okazuje się być wskazówką; dla interpretera języka typ jawi się jako obiekt 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 przycisk Ponowne uruchamianieIkona z przyciskiem uruchamiania aplikacji na pasku narzędzi Debug. na pasku narzędzi debugowania (Ctrl + Shift + F5), aby skompilować kod i uruchomić ponownie.

    Teraz, gdy debuger wstrzymuje się na Console.WriteLine, możesz zatrzymać wskaźnik myszy na theGalaxy.GalaxyType.MyGType, i 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 polecenie 'Usuń punkt przerwania' 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).

    public GType(char type)
    

    Ten kod to miejsce, gdzie ustawia się typ galaktyki, więc chcemy przyjrzeć się temu bliżej.

  12. Wybierz Restartikonę pokazującą przycisk Uruchom ponownie aplikację na pasku narzędzi Debug. na pasku narzędzi Debug (Ctrl + Shift + F5), aby ponownie uruchomić.

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

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

  14. Naciśnij F5 i ponownie umieść kursor nad zmienną 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 (Debuguj>krok do).

  16. Naciśnij F11, dopóki nie zatrzymasz się w instrukcji switch dla wartości 'I' (wyrażenie Select w języku Visual Basic). W tym miejscu zobaczysz wyraźny problem wynikający z literówki. Oczekiwano, że kod przechodzi do lokalizacji, w której MyGType jest ustawiany jako typu galaktyki Nieregularny, ale debuger pomija ten kod całkowicie i wstrzymuje się w sekcji default instrukcji switch (instrukcja Else w Visual Basic).

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

    W instrukcji case 'l' patrząc na kod, widać literówkę. Powinna ona mieć wartość case 'I'.

  17. Wybierz fragment kodu case 'l' i zastąp go elementem 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ę.

Podsumowanie

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

Uwaga / 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 Dane wyjściowe . 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 nieprawidłową wartość, sprawdź, gdzie ustawiono nieprawidłową wartość (aby znaleźć, gdzie ustawiono wartość, może być konieczne ponowne uruchomienie debugera, przyjrzenie się stosowi wywołań lub obu).

  • 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ę).

Wskazówka

Debuger ułatwia znajdowanie usterek. Narzędzie do debugowania może znaleźć usterki tylko wtedy, gdy zna intencję kodu. Narzędzie może znać intencję kodu tylko wtedy, gdy deweloper wyrazi ten zamiar. Pisanie testów jednostkowych to sposób, w jaki to robisz.

Dalsze kroki

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