Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Att åtgärda buggar och fel i koden kan vara en tidskrävande och ibland frustrerande uppgift. Det tar tid att lära sig att felsöka effektivt. En kraftfull IDE som Visual Studio kan göra ditt jobb mycket enklare. En IDE kan hjälpa dig att åtgärda fel och felsöka koden snabbare och hjälpa dig att skriva bättre kod med färre buggar. Den här artikeln innehåller en holistisk vy över "felkorrigeringsprocessen", så att du kan veta när du ska använda kodanalysatorn, när du ska använda felsökningsprogrammet, hur du åtgärdar undantag och hur du kodar för avsikt. Om du redan vet att du behöver använda felsökningsprogrammet läser du Först titta på felsökningsprogrammet.
I den här artikeln får du lära dig hur du arbetar med IDE för att göra dina kodningssessioner mer produktiva. Vi berör flera uppgifter, till exempel:
- Förbereda koden för felsökning med hjälp av IDE:s kodanalys 
- Så här åtgärdar du undantag (körningsfel) 
- Så här minimerar du buggar genom att koda för avsikt (med hjälp av assert) 
- När du ska använda felsökningsprogrammet 
För att demonstrera dessa uppgifter visar vi några av de vanligaste typerna av fel och buggar som du kan stöta på när du försöker felsöka dina appar. Även om exempelkoden är C#, gäller den konceptuella informationen vanligtvis för C++, Visual Basic, JavaScript och andra språk som stöds av Visual Studio (förutom där det anges). Skärmbilderna finns i C#.
Skapa en exempelapp med några buggar och fel i den
Följande kod innehåller några buggar som du kan åtgärda med hjälp av Visual Studio IDE. Det här programmet är en enkel app som simulerar hämtar JSON-data från en viss åtgärd, deserialiserar data till ett objekt och uppdaterar en enkel lista med nya data.
Om du vill skapa appen måste du ha Visual Studio installerat och arbetsbelastningen för .NET-skrivbordsutveckling installerad.
- Om du inte redan har installerat Visual Studio går du till Visual Studio-nedladdningar sidan för att installera den kostnadsfritt. 
- Om du behöver installera arbetsbelastningen men redan har Visual Studio väljer du Verktyg>Hämta verktyg och funktioner. Visual Studio Installer startas. Välj arbetsbelastningen för .NET-skrivbordsutveckling och välj då Ändra. 
Följ de här stegen för att skapa programmet:
- Öppna Visual Studio. I startfönstret väljer du Skapa ett nytt projekt. 
- I sökrutan anger du konsolen och sedan ett av konsolappalternativen för .NET. 
- Välj Nästa. 
- Ange ett projektnamn som Console_Parse_JSON och välj sedan Nästa eller Skapa efter behov. - Välj antingen det rekommenderade målramverket eller .NET 8 och välj sedan Skapa. - Om du inte ser projektmallen Konsolapp för .NET går du till Verktyg>Hämta verktyg och funktioner, som öppnar Installationsprogrammet för Visual Studio. Välj arbetsbelastningen för .NET-skrivbordsutveckling och välj då Ändra. - Visual Studio skapar konsolprojektet som visas i Solution Explorer i den högra rutan. 
När projektet är klart ersätter du standardkoden i projektets Program.cs-fil med följande exempelkod:
using System;
using System.Collections.Generic;
using System.Runtime.Serialization.Json;
using System.Runtime.Serialization;
using System.IO;
namespace Console_Parse_JSON
{
    class Program
    {
        static void Main(string[] args)
        {
            var localDB = LoadRecords();
            string data = GetJsonData();
            User[] users = ReadToObject(data);
            UpdateRecords(localDB, users);
            for (int i = 0; i < users.Length; i++)
            {
                List<User> result = localDB.FindAll(delegate (User u) {
                    return u.lastname == users[i].lastname;
                    });
                foreach (var item in result)
                {
                    Console.WriteLine($"Matching Record, got name={item.firstname}, lastname={item.lastname}, age={item.totalpoints}");
                }
            }
            Console.ReadKey();
        }
        // Deserialize a JSON stream to a User object.
        public static User[] ReadToObject(string json)
        {
            User deserializedUser = new User();
            User[] users = { };
            MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json));
            DataContractJsonSerializer ser = new DataContractJsonSerializer(users.GetType());
            users = ser.ReadObject(ms) as User[];
            ms.Close();
            return users;
        }
        // Simulated operation that returns JSON data.
        public static string GetJsonData()
        {
            string str = "[{ \"points\":4o,\"firstname\":\"Fred\",\"lastname\":\"Smith\"},{\"lastName\":\"Jackson\"}]";
            return str;
        }
        public static List<User> LoadRecords()
        {
            var db = new List<User> { };
            User user1 = new User();
            user1.firstname = "Joe";
            user1.lastname = "Smith";
            user1.totalpoints = 41;
            db.Add(user1);
            User user2 = new User();
            user2.firstname = "Pete";
            user2.lastname = "Peterson";
            user2.totalpoints = 30;
            db.Add(user2);
            return db;
        }
        public static void UpdateRecords(List<User> db, User[] users)
        {
            bool existingUser = false;
            for (int i = 0; i < users.Length; i++)
            {
                foreach (var item in db)
                {
                    if (item.lastname == users[i].lastname && item.firstname == users[i].firstname)
                    {
                        existingUser = true;
                        item.totalpoints += users[i].points;
                    }
                }
                if (existingUser == false)
                {
                    User user = new User();
                    user.firstname = users[i].firstname;
                    user.lastname = users[i].lastname;
                    user.totalpoints = users[i].points;
                    db.Add(user);
                }
            }
        }
    }
    [DataContract]
    internal class User
    {
        [DataMember]
        internal string firstname;
        [DataMember]
        internal string lastname;
        [DataMember]
        // internal double points;
        internal string points;
        [DataMember]
        internal int totalpoints;
    }
}
Hitta de röda och gröna krumelurerna!
Innan du försöker starta exempelappen och köra felsökningsprogrammet, kontrollera koden i kodredigeraren efter röda och gröna vågiga understrykningar. Dessa representerar fel och varningar som identifieras av IDE:s kodanalysator. De röda squigglesna är kompileringstidsfel, som du måste åtgärda innan du kan köra koden. De gröna squigglesna är varningar. Även om du ofta kan köra din app utan att åtgärda varningarna kan de vara en källa till buggar och du sparar ofta tid och problem genom att undersöka dem. Dessa varningar och fel visas också i fönstret Fellista om du föredrar en listvy.
I exempelappen ser du flera röda krumelurer att åtgärda och en grön som du ska undersöka. Här är det första felet.
               
              
            
Om du vill åtgärda det här felet kan du titta på en annan funktion i IDE:t, som representeras av glödlampans ikon.
Kontrollera glödlampan!
Den första röda krusidullen representerar ett kompileringsfel. Hovra över det så ser du meddelandet The name `Encoding` does not exist in the current context.
Observera att det här felet visar en glödlampa ikon längst ned till vänster. Tillsammans med skruvmejselikonens 
 glödlampaikonen snabbåtgärder som kan hjälpa dig att åtgärda eller omstrukturera kod infogad. Glödlampan representerar problem som du bör åtgärda. Skruvmejseln är avsedd för problem som du kan välja att åtgärda. Använd den första föreslagna korrigeringen för att lösa det här felet genom att klicka på System.Text till vänster.
 glödlampaikonen snabbåtgärder som kan hjälpa dig att åtgärda eller omstrukturera kod infogad. Glödlampan representerar problem som du bör åtgärda. Skruvmejseln är avsedd för problem som du kan välja att åtgärda. Använd den första föreslagna korrigeringen för att lösa det här felet genom att klicka på System.Text till vänster.
               
              
            
När du väljer det här objektet lägger Visual Studio till -instruktionen using System.Text överst i filen Program.cs och det röda vågiga strecket försvinner. (När du är osäker på ändringar som tillämpas av en föreslagen korrigering väljer du länken Förhandsgranska ändringar till höger innan du tillämpar korrigeringen.)
Föregående fel är vanligt och du brukar åtgärda det genom att lägga till en ny using instruktion i koden. Det finns flera vanliga, liknande fel som The type or namespace "Name" cannot be found. den här typen av fel kan tyda på en saknade sammansättningsreferens (högerklicka på projektet, välj Lägg till>referens), ett felstavat namn eller ett bibliotek som saknas som du behöver lägga till (för C#högerklickar du på projektet och väljer Hantera NuGet-paket).
Åtgärda återstående fel och varningar
Det finns några fler markeringar att granska i den här koden. Här visas ett vanligt typkonverteringsfel. När du håller muspekaren över krumeluren ser du att koden försöker konvertera en sträng till en int, vilket inte stöds utan att du lägger till uttalad kod för att göra konverteringen.
               
              
            
Eftersom kodanalysatorn inte kan gissa din avsikt finns det inga glödlampor som hjälper dig den här gången. För att åtgärda det här felet måste du känna till avsikten med koden. I det här exemplet är det inte så svårt att se att points ska vara ett numeriskt värde (heltal), eftersom du försöker lägga till points till totalpoints.
Åtgärda det här felet genom att ändra points medlemmen i klassen User från följande:
[DataMember]
internal string points;
till detta:
[DataMember]
internal int points;
De röda vågiga raderna i kodredigeraren försvinner.
Hovra sedan över den gröna vågiga linjen i datamedlemmens points deklaration. Kodanalysen anger att variabeln aldrig har tilldelats något värde.
               
              
            
Detta representerar vanligtvis ett problem som måste åtgärdas. I exempelappen lagrar du dock data i variabeln points under deserialiseringsprocessen och lägger sedan till det värdet till totalpoints datamedlemmen. I det här exemplet känner du till avsikten med koden och kan ignorera varningen på ett säkert sätt. Men om du vill eliminera varningen kan du ersätta följande kod:
item.totalpoints = users[i].points;
med detta:
item.points = users[i].points;
item.totalpoints += users[i].points;
Den gröna squigglen försvinner.
Åtgärda ett undantag
När du har korrigerat alla röda squiggles och löst – eller åtminstone undersökt – alla gröna squiggles är du redo att starta felsökningsprogrammet och köra appen.
Tryck på F5 (Felsök > Starta felsökning) eller starta felsökningsknappen i verktygsfältet Felsökning.
 i verktygsfältet Felsökning.
Nu genererar exempelappen ett SerializationException undantag (ett körningsfel). Det vill säga att appen har problem med den data den försöker serialisera. Eftersom du startade appen i felsökningsläge (felsökningsprogrammet bifogat) tar felsökningsprogrammets undantagshjälp dig direkt till koden som utlöste undantaget och ger dig ett användbart felmeddelande.
               
              
            
Felmeddelandet instruerar dig att värdet 4o inte kan parsas som ett heltal. Så i det här exemplet vet du att data är dåliga: 4o bör vara 40. Men om du inte har kontroll över data i ett verkligt scenario (säg att du får dem från en webbtjänst), vad gör du åt det? Hur åtgärdar du detta?
När du stöter på ett undantag måste du ställa (och besvara) ett par frågor:
- Är det här undantaget bara en bugg som du kan åtgärda? Eller: 
- Är det här undantaget något som användarna kan stöta på? 
Om det är den förra, åtgärda buggen. (I exempelappen måste du åtgärda felaktiga data.) Om det är det senare kan du behöva hantera undantaget i koden med hjälp av ett try/catch block (vi tittar på andra möjliga strategier i nästa avsnitt). Ersätt följande kod i exempelappen:
users = ser.ReadObject(ms) as User[];
med den här koden:
try
{
    users = ser.ReadObject(ms) as User[];
}
catch (SerializationException)
{
    Console.WriteLine("Give user some info or instructions, if necessary");
    // Take appropriate action for your app
}
Ett try/catch block har en viss prestandakostnad, så du vill bara använda dem när du verkligen behöver dem, det vill: där (a) de kan uppstå i versionen av appen och där (b) dokumentationen för metoden anger att du bör söka efter undantaget (förutsatt att dokumentationen är klar!). I många fall kan du hantera ett undantag på rätt sätt och användaren behöver aldrig känna till det.
Här följer några viktiga tips för undantagshantering:
- Undvik att använda ett tomt catch-block, till exempel - catch (Exception) {}, som inte vidtar lämpliga åtgärder för att exponera eller hantera ett fel. Ett tomt eller icke-informativt catch-block kan dölja undantag och göra koden svårare att felsöka i stället för enklare.
- try/catchAnvänd blocket runt den specifika funktion som utlöser undantaget (- ReadObjecti exempelappen). Om du använder den runt ett större kodsegment döljer du platsen för felet. Använd till exempel inte- try/catchblocket runt anropet till den överordnade funktionen- ReadToObject, som visas här, eller så vet du inte exakt var undantaget inträffade.- // Don't do this try { User[] users = ReadToObject(data); } catch (SerializationException) { }
- För obekanta funktioner som du inkluderar i din app, särskilt funktioner som interagerar med externa data (till exempel en webbbegäran), läser du dokumentationen för att se vilka undantag som funktionen sannolikt kommer att utlösa. Detta kan vara viktig information för korrekt felhantering och för felsökning av din app. 
För exempelappen korrigera SerializationException i GetJsonData metoden genom att ändra 4o till 40.
Tips/Råd
Om du har Copilotkan du få AI-hjälp när du felsöker undantag. Leta bara efter Fråga Copilot knapp. Mer information finns i Felsöka med Copilot.
 knapp. Mer information finns i Felsöka med Copilot.
Förtydliga din kod avsikt med hjälp av assert
Välj knappen Starta om i verktygsfältet Felsök (Ctrl + Skift + F5). Detta startar om appen i färre steg. Du ser följande utdata i konsolfönstret.
 i verktygsfältet Felsök (Ctrl + Skift + F5). Detta startar om appen i färre steg. Du ser följande utdata i konsolfönstret.
               
              
            
Du kan se att något i utdata inte stämmer. namn och efternamn-värdena för den tredje posten är tomma!
Det här är ett bra tillfälle att prata om en användbar kodningspraxis, ofta underutnyttad, som är att använda assert -instruktioner i dina funktioner. Genom att lägga till följande kod inkluderar du en kontroll under körning för att se till att firstname och lastname inte är null. Ersätt följande kod i UpdateRecords metoden:
if (existingUser == false)
{
    User user = new User();
    user.firstname = users[i].firstname;
    user.lastname = users[i].lastname;
med detta:
// Also, add a using statement for System.Diagnostics at the start of the file.
Debug.Assert(users[i].firstname != null);
Debug.Assert(users[i].lastname != null);
if (existingUser == false)
{
    User user = new User();
    user.firstname = users[i].firstname;
    user.lastname = users[i].lastname;
Genom att lägga till assert instruktioner som detta i dina funktioner under utvecklingsprocessen kan du ange avsikten med din kod. I föregående exempel anger vi följande objekt:
- En giltig sträng krävs för förnamnet
- En giltig sträng krävs för efternamnet
Genom att ange avsikt på det här sättet framtvingar du dina krav. Det här är en enkel och praktisk metod som du kan använda för att visa buggar under utvecklingen. (assert-instruktioner används också som huvudkomponent i enhetstester.)
Välj knappen Starta om i verktygsfältet Debugg (Ctrl + Skift + F5).
 i verktygsfältet Debugg (Ctrl + Skift + F5).
Anmärkning
Koden assert är endast aktiv i en felsökningsversion.
När du startar om pausar debuggern på instruktionen assert eftersom uttrycket users[i].firstname != null utvärderas till false i stället för true.
               
              
            
Felet assert anger att det finns ett problem som du behöver undersöka. 
              assert kan omfatta många scenarier där du inte nödvändigtvis ser ett undantag. I det här exemplet ser användaren inget undantag och ett null värde läggs till som firstname i listan med poster. Det här villkoret kan orsaka problem senare (till exempel i konsolens utdata) och kan vara svårare att felsöka.
Anmärkning
I scenarier där du anropar en metod på null värdet, uppstår NullReferenceException. Du vill normalt undvika att använda ett try/catch block för ett allmänt undantag, dvs. ett undantag som inte är kopplat till den specifika biblioteksfunktionen. Alla objekt kan utlösa en NullReferenceException. Kontrollera dokumentationen för biblioteksfunktionen om du inte är säker.
Under felsökningsprocessen är det bra att behålla en viss assert instruktion tills du vet att du behöver ersätta den med en faktisk kodkorrigering. Anta att du bestämmer dig för att användaren kan råka ut för undantaget i en släppversion av appen. I så fall måste du omstrukturera kod för att se till att appen inte utlöser ett allvarligt undantag eller resulterar i något annat fel. För att åtgärda den här koden ersätter du följande kod:
if (existingUser == false)
{
    User user = new User();
med den här koden:
if (existingUser == false && users[i].firstname != null && users[i].lastname != null)
{
    User user = new User();
Genom att använda den här koden uppfyller du dina kodkrav och ser till att en post med ett värde av firstname eller lastname eller ett null värde inte läggs till i datan.
I det här exemplet har vi lagt till de två assert uttrycken i en loop. När du använder assertär det vanligtvis bäst att lägga assert till instruktioner vid startpunkten (början) för en funktion eller metod. Du tittar för närvarande på UpdateRecords metoden i exempelappen. I den här metoden vet du att du har problem om något av metodargumenten är null, så kontrollera dem båda med en assert -instruktion vid funktionens startpunkt.
public static void UpdateRecords(List<User> db, User[] users)
{
    Debug.Assert(db != null);
    Debug.Assert(users != null);
För föregående instruktioner är avsikten att du läser in befintliga data (db) och hämtar nya data (users) innan du uppdaterar något.
Du kan använda assert med alla typer av uttryck som matchar till true eller false. Du kan till exempel lägga till en assert instruktion som den här.
Debug.Assert(users[0].points > 0);
Föregående kod är användbar om du vill ange följande avsikt: ett nytt punktvärde som är större än noll (0) krävs för att uppdatera användarens post.
Kontrollera koden i felsökningsprogrammet
OK, nu när du har åtgärdat allt som är kritiskt som är fel med exempelappen kan du gå vidare till andra viktiga saker!
Vi visade dig felsökarens undantagshjälp, men felsökningsprogrammet är ett mycket kraftfullare verktyg som också gör att du kan göra andra saker som att gå igenom koden och inspektera dess variabler. Dessa mer kraftfulla funktioner är användbara i många scenarier, särskilt följande scenarier:
- Du försöker isolera ett körningsfel i koden, men kan inte göra det med hjälp av metoder och verktyg som tidigare diskuterats. 
- Du vill verifiera din kod, det vill: titta på den medan den körs för att se till att den beter sig på det sätt du förväntar dig och gör vad du vill. - Det är lärorikt att titta på koden medan den körs. Du kan lära dig mer om din kod på det här sättet och kan ofta identifiera buggar innan de visar några uppenbara symtom. 
Information om hur du använder de viktigaste funktionerna i felsökningsprogrammet finns i Felsökning för absoluta nybörjare.
Åtgärda prestandaproblem
Buggar av en annan typ inkluderar ineffektiv kod som gör att appen körs långsamt eller använder för mycket minne. I allmänhet är optimering av prestanda något du gör senare i din apputveckling. Du kan dock stöta på prestandaproblem tidigt (du ser till exempel att en del av din app går långsamt) och du kan behöva testa din app med profileringsverktygen tidigt. Mer information om profileringsverktyg som cpu-användningsverktyget och Minnesanalys finns i Titta först på profileringsverktygen.
Relaterat innehåll
I den här artikeln har du lärt dig hur du undviker och åtgärdar många vanliga buggar i koden och när du ska använda felsökningsprogrammet. Läs sedan mer om hur du använder Visual Studio-felsökningsprogrammet för att åtgärda buggar.