Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Het oplossen van fouten en fouten in uw code kan een tijdrovende en soms frustrerende taak zijn. Het kost tijd om te leren hoe u effectief fouten kunt opsporen. Een krachtige IDE zoals Visual Studio kan uw taak veel eenvoudiger maken. Een IDE kan u helpen fouten op te lossen en sneller fouten in uw code op te sporen en u te helpen betere code te schrijven met minder fouten. Dit artikel biedt een holistische weergave van het 'bugfixing'-proces, zodat u kunt weten wanneer u de codeanalyse moet gebruiken, wanneer u het foutopsporingsprogramma gebruikt, hoe uitzonderingen moeten worden opgelost en hoe u code voor intentie moet codeeren. Als u al weet dat u het foutopsporingsprogramma moet gebruiken, raadpleegt u eerst het foutopsporingsprogramma.
In dit artikel leert u hoe u met de IDE kunt werken om uw coderingssessies productiever te maken. We raken verschillende taken aan, zoals:
Bereid uw code voor op foutopsporing met behulp van de codeanalyse van de IDE
Uitzonderingen oplossen (runtimefouten)
Fouten minimaliseren door te coderen voor intentie (met behulp van assert)
Wanneer gebruikt u het foutopsporingsprogramma?
Om deze taken te demonstreren, laten we een aantal van de meest voorkomende typen fouten en fouten zien die u kunt tegenkomen bij het opsporen van fouten in uw apps. Hoewel de voorbeeldcode C# is, is de conceptuele informatie meestal van toepassing op C++, Visual Basic, JavaScript en andere talen die worden ondersteund door Visual Studio (behalve waar vermeld). De schermopnamen bevinden zich in C#.
Een voorbeeld-app maken met enkele bugs en fouten erin
De volgende code bevat enkele fouten die u kunt oplossen met behulp van de Visual Studio IDE. Deze toepassing is een eenvoudige app die het ophalen van JSON-gegevens van een bepaalde bewerking simuleert, deserialiseert de gegevens naar een object en een eenvoudige lijst bijwerkt met de nieuwe gegevens.
Als u de app wilt maken, moet Visual Studio zijn geïnstalleerd en moet de workload voor .NET-desktopontwikkeling zijn geïnstalleerd.
Als u Visual Studio nog niet hebt geïnstalleerd, gaat u naar de Visual Studio-downloadpagina pagina om deze gratis te installeren.
Als u de workload wilt installeren maar Visual Studio al hebt, kunt u Hulpprogramma's>Tools en functies ophalen selecteren. Het installatieprogramma van Visual Studio wordt gestart. Kies de .NET-desktopontwikkelingswerklast en selecteer vervolgens Wijzigen.
Volg deze stappen om de toepassing te maken:
Open Visual Studio. Selecteer een nieuw project maken in het startvenster.
Voer in het zoekvak console in en voer vervolgens een van de console-app-opties voor .NET in.
Kies Volgende.
Voer een projectnaam in zoals Console_Parse_JSON, en selecteer Volgende of Maken, indien van toepassing.
Kies het aanbevolen doelnetwerk of .NET 8, en klik daarna op Maken.
Als u de console-app voor .NET-projectsjabloon niet ziet, gaat u naar ToolsGet Tools >and Features, waarmee het Installatieprogramma van Visual Studio wordt geopend. Kies de .NET-desktopontwikkelingswerklast en selecteer vervolgens Wijzigen.
Visual Studio maakt het consoleproject, dat wordt weergegeven in Solution Explorer in het rechterdeelvenster.
Wanneer het project klaar is, vervangt u de standaardcode in het Program.cs-bestand van het project door de volgende voorbeeldcode:
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;
}
}
Zoek de rode en groene wiebels!
Voordat u de voorbeeldapp start en de debugger uitvoert, controleert u de code in de code-editor op rode en groene golflijnen. Deze vertegenwoordigen fouten en waarschuwingen die worden geïdentificeerd door de codeanalyse van de IDE. De rode golvende lijnen zijn compilatiefouten, die u moet oplossen voordat u de code kunt uitvoeren. De groene kronkeltjes zijn waarschuwingen. Hoewel u uw app vaak kunt uitvoeren zonder de waarschuwingen op te lossen, kunnen ze een bron van bugs zijn en bespaart u vaak tijd en problemen door ze te onderzoeken. Deze waarschuwingen en fouten worden ook weergegeven in het venster Foutenlijst als u liever een lijstweergave hebt.
In de voorbeeld-app ziet u verschillende rode kronkels die u moet herstellen en een groene die u moet onderzoeken. Dit is de eerste fout.
U kunt deze fout oplossen door een andere functie van de IDE te bekijken, vertegenwoordigd door het gloeilamppictogram.
Controleer de gloeilamp!
De eerste rode golvende lijn vertegenwoordigt een compilatietijdfout. Beweeg de muisaanwijzer erover en u ziet het bericht The name `Encoding` does not exist in the current context.
U ziet dat deze fout een gloeilamppictogram linksonder weergeeft. Samen met het pictogram ![]()
het gloeilamppictogram snelle acties waarmee u code inline kunt herstellen of herstructureren. De gloeilamp vertegenwoordigt problemen die u moet oplossen. De schroevendraaier is bedoeld voor problemen die u kunt oplossen. Gebruik de eerste voorgestelde oplossing om deze fout op te lossen door aan de linkerkant op System.Text te klikken.
Wanneer u dit item selecteert, voegt Visual Studio de using System.Text instructie toe boven aan het Program.cs-bestand en verdwijnt de rode golvende rand. (Als u niet zeker weet welke wijzigingen zijn toegepast door een voorgestelde oplossing, kiest u de koppeling Voorbeeldwijzigingen aan de rechterkant voordat u de fix toepast.)
De voorgaande fout is een veelvoorkomende fout die u meestal oplost door een nieuwe using instructie toe te voegen aan uw code. Er zijn verschillende veelvoorkomende, vergelijkbare fouten als deze, zoals The type or namespace "Name" cannot be found. dit soort fouten, kunnen duiden op een ontbrekende assemblyverwijzing (klik met de rechtermuisknop op het project, kiesVerwijzing>), een verkeerd gespelde naam of een ontbrekende bibliotheek die u moet toevoegen (klik voor C# met de rechtermuisknop op het project en kies NuGet-pakketten beheren).
De resterende fouten en waarschuwingen oplossen
Er zijn nog enkele kronkels om in deze code te bekijken. Hier ziet u een veelvoorkomende typeconversiefout. Wanneer u de muisaanwijzer boven het golflijntje houdt, ziet u dat de code probeert een tekenreeks naar een int te converteren, wat niet wordt ondersteund tenzij u expliciete code toevoegt voor de conversie.
Omdat de code analyzer uw intentie niet kan raden, zijn er geen gloeilampen om u deze keer te helpen. U kunt deze fout oplossen door de intentie van de code te kennen. In dit voorbeeld is het niet te moeilijk om te zien dat dit points een numerieke waarde (geheel getal) moet zijn, omdat u probeert toe te voegen points aan totalpoints.
U kunt deze fout oplossen door het points lid van de User klasse als volgt te wijzigen:
[DataMember]
internal string points;
om dit te doen:
[DataMember]
internal int points;
De rode golvende lijnen in de code-editor gaan weg.
Beweeg vervolgens de muisaanwijzer over de groene kronkel in de declaratie van het points gegevenslid. De codeanalyse vertelt u dat er nooit een waarde aan de variabele wordt toegewezen.
Dit is meestal een probleem dat moet worden opgelost. In de voorbeeld-app slaat u echter gegevens in de points variabele op tijdens het deserialisatieproces en voegt u die waarde vervolgens toe aan het totalpoints gegevenslid. In dit voorbeeld kent u de intentie van de code en kunt u de waarschuwing veilig negeren. Als u de waarschuwing echter wilt elimineren, kunt u de volgende code vervangen:
item.totalpoints = users[i].points;
hiermee:
item.points = users[i].points;
item.totalpoints += users[i].points;
De groene kronkel gaat weg.
Een uitzondering oplossen
Wanneer u alle rode markeringen hebt opgelost en alle groene markeringen hebt opgelost of ten minste hebt onderzocht, bent u klaar om de debugger te starten en de app uit te voeren.
Druk op F5 (Start foutopsporing>) of op de knop
in de werkbalk Foutopsporing.
Op dit moment genereert de voorbeeld-app een SerializationException uitzondering (een runtimefout). Dat wil zeggen, de app verstikt in de gegevens die het probeert te serialiseren. Omdat u de app hebt gestart in de foutopsporingsmodus (bijgevoegd foutopsporingsprogramma), gaat u met de Uitzonderingshulpfunctie van het foutopsporingsprogramma rechtstreeks naar de code die de uitzondering heeft veroorzaakt en krijgt u een nuttig foutbericht.
In het foutbericht wordt aangegeven dat de waarde 4o niet kan worden geparseerd als een geheel getal. In dit voorbeeld weet u dus dat de gegevens slecht zijn: 4o moet zijn 40. Als u echter geen controle hebt over de gegevens in een echt scenario (stel dat u deze uit een webservice krijgt), wat doet u eraan? Hoe lost u dit op?
Wanneer u een uitzondering bereikt, moet u een aantal vragen stellen (en beantwoorden):
Is deze uitzondering slechts een fout die u kunt oplossen? Of
Is deze uitzondering iets dat uw gebruikers kunnen tegenkomen?
Als het dat eerste is, los de fout op. (In de voorbeeld-app moet u de slechte gegevens herstellen.) Als dit laatste het geval is, moet u mogelijk de uitzondering in uw code afhandelen met behulp van een try/catch blok (in de volgende sectie kijken we naar andere mogelijke strategieën). Vervang in de voorbeeld-app de volgende code:
users = ser.ReadObject(ms) as User[];
met deze code:
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
}
Een try/catch blok heeft een aantal prestatiekosten, dus u wilt ze alleen gebruiken wanneer u ze echt nodig hebt, dat wil weten waar (a) ze kunnen voorkomen in de releaseversie van de app en waarbij (b) de documentatie voor de methode aangeeft dat u moet controleren op de uitzondering (ervan uitgaande dat de documentatie is voltooid!). In veel gevallen kunt u een uitzondering op de juiste wijze afhandelen en hoeft de gebruiker er nooit over te weten.
Hier volgen enkele belangrijke tips voor het afhandelen van uitzonderingen:
Vermijd het gebruik van een leeg catch-blok, zoals
catch (Exception) {}, dat niet de juiste actie onderneemt om een fout weer te geven of af te handelen. Een leeg of niet-informatief catch-blok kan uitzonderingen verbergen en uw code lastiger maken om fouten op te sporen in plaats van eenvoudiger.Gebruik het
try/catchblok rond de specifieke functie waarmee de uitzondering wordt gegenereerd (ReadObjectin de voorbeeld-app). Als u deze gebruikt rond een groter stuk code, verbergt u de locatie van de fout. Gebruik bijvoorbeeld niet hettry/catchblok rond de aanroep naar de bovenliggende functieReadToObject, die hier wordt weergegeven, of u weet niet precies waar de uitzondering is opgetreden.// Don't do this try { User[] users = ReadToObject(data); } catch (SerializationException) { }Voor onbekende functies die u in uw app opneemt, met name functies die communiceren met externe gegevens (zoals een webaanvraag), raadpleegt u de documentatie om te zien welke uitzonderingen de functie waarschijnlijk zal genereren. Dit kan kritieke informatie zijn voor de juiste foutafhandeling en voor het opsporen van fouten in uw app.
Corrigeer voor de voorbeeld-app de SerializationException in de GetJsonData-methode door 4o te wijzigen in 40.
Aanbeveling
Als u Copilothebt, kunt u AI-hulp krijgen tijdens het opsporen van uitzonderingen. Zoek naar de Ask Copilot
knop. Zie Fouten opsporen met Copilotvoor meer informatie.
Uw code-intentie verduidelijken met behulp van assert
Selecteer de knop
op de werkbalk Foutopsporing (Ctrl + Shift + F5). Hierdoor wordt de app in minder stappen opnieuw opgestart. U ziet de volgende uitvoer in het consolevenster.
U kunt zien dat iets in deze uitvoer niet klopt. De naam - en achternaamwaarden voor de derde record zijn leeg.
Dit is een goed moment om te praten over een nuttige coderingspraktijk, vaak onderbenut, namelijk het gebruik van assert instructies in uw functies. Door de volgende code toe te voegen, neemt u een runtimecontrole op om er zeker van te zijn dat firstname en lastname niet null. Vervang de volgende code in de UpdateRecords methode:
if (existingUser == false)
{
User user = new User();
user.firstname = users[i].firstname;
user.lastname = users[i].lastname;
hiermee:
// 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;
Door tijdens het ontwikkelingsproces instructies zoals deze toe te voegen assert aan uw functies, kunt u helpen bij het opgeven van de intentie van uw code. In het voorgaande voorbeeld geven we de volgende items op:
- Een geldige tekenreeks is vereist voor de voornaam
- Er is een geldige tekenreeks vereist voor de achternaam
Door de intentie op deze manier op te geven, dwingt u uw vereisten af. Dit is een eenvoudige en handige methode die u kunt gebruiken om fouten op te sporen tijdens de ontwikkeling. (assert uitspraken worden ook gebruikt als het belangrijkste element in unit tests.)
Selecteer de knop
op de werkbalk Foutopsporing (Ctrl + Shift + F5).
Opmerking
De assert code is alleen actief in een build voor foutopsporing.
Als u opnieuw opstart, pauzeert het foutopsporingsprogramma bij de assert instructie, omdat de expressie users[i].firstname != null tot false leidt in plaats van true.
De assert fout geeft aan dat er een probleem is dat u moet onderzoeken.
assert kan betrekking hebben op veel scenario's waarbij u niet per se een uitzondering ziet. In dit voorbeeld ziet de gebruiker geen uitzondering en wordt een null waarde toegevoegd zoals firstname in uw lijst met records. Deze voorwaarde kan later problemen veroorzaken (zoals u in de console-uitvoer ziet) en kan lastiger zijn om fouten op te sporen.
Opmerking
In scenario's waarin u een methode aanroept voor de null waarde, zal er een NullReferenceException optreden. Normaal gesproken wilt u voorkomen dat u een try/catch blok gebruikt voor een algemene uitzondering, dat wil bijvoorbeeld een uitzondering die niet is gekoppeld aan de specifieke bibliotheekfunctie. Elk object kan een NullReferenceException veroorzaken. Raadpleeg de documentatie voor de bibliotheekfunctie als u het niet zeker weet.
Tijdens het debuggingproces kunt u een bepaalde assert instructie behouden totdat u zeker weet dat deze moet worden vervangen door een definitieve codeoplossing. Stel dat u besluit dat de gebruiker de uitzondering kan tegenkomen in een release-build van de app. In dat geval moet u code herstructureren om ervoor te zorgen dat uw app geen fatale uitzondering genereert of een andere fout veroorzaakt. Vervang dus de volgende code om deze code op te lossen:
if (existingUser == false)
{
User user = new User();
met deze code:
if (existingUser == false && users[i].firstname != null && users[i].lastname != null)
{
User user = new User();
Door deze code te gebruiken, voldoet u aan uw codevereisten en zorgt u ervoor dat een record met een firstname of lastname waarde null ervan niet aan de gegevens wordt toegevoegd.
In dit voorbeeld hebben we de twee assert instructies in een lus toegevoegd. Wanneer u assert gebruikt, is het het beste om assert statements toe te voegen aan het beginpunt (begin) van een functie of methode. U bekijkt momenteel de UpdateRecords methode in de voorbeeld-app. In deze methode weet u dat u problemen ondervindt als een van de methodeargumenten is null, dus controleer ze beide met een assert instructie op het toegangspunt van de functie.
public static void UpdateRecords(List<User> db, User[] users)
{
Debug.Assert(db != null);
Debug.Assert(users != null);
Voor de voorgaande instructies is uw bedoeling dat u bestaande gegevens laadt (db) en nieuwe gegevens (users) ophaalt voordat u iets bijwerkt.
Gebruik assert met elk type expressie die resulteert in true of false. U kunt bijvoorbeeld een assert instructie zoals deze toevoegen.
Debug.Assert(users[0].points > 0);
De voorgaande code is handig als u de volgende intentie wilt opgeven: een nieuwe puntwaarde groter dan nul (0) is vereist om de record van de gebruiker bij te werken.
Controleer uw code in het foutopsporingsprogramma
Nu u alles hebt opgelost dat essentieel is voor de voorbeeld-app, kunt u doorgaan naar andere belangrijke dingen.
We hebben u de Uitzonderingshelper van het foutopsporingsprogramma laten zien, maar het foutopsporingsprogramma is een veel krachtiger hulpprogramma waarmee u ook andere dingen kunt doen, zoals het doorlopen van uw code en het inspecteren van de variabelen. Deze krachtigere mogelijkheden zijn nuttig in veel scenario's, met name in de volgende scenario's:
U probeert een runtimefout in uw code te isoleren, maar u kunt dit niet doen met behulp van methoden en hulpprogramma's die eerder zijn besproken.
U wilt uw code valideren, dat wil gezegd, deze bekijken terwijl deze wordt uitgevoerd om ervoor te zorgen dat deze zich gedraagt op de manier die u verwacht en doet wat u wilt.
Het is instructief om uw code te bekijken terwijl deze wordt uitgevoerd. U kunt op deze manier meer informatie krijgen over uw code en fouten vaak identificeren voordat ze duidelijke symptomen vertonen.
Zie Foutopsporing voor absolute beginners voor meer informatie over het gebruik van de essentiële functies van het foutopsporingsprogramma.
Prestatieproblemen oplossen
Bugs van een ander type bevatten inefficiënte code die ervoor zorgt dat uw app langzaam wordt uitgevoerd of te veel geheugen gebruikt. Over het algemeen is het optimaliseren van de prestaties iets wat u later in de ontwikkeling van uw app doet. U kunt echter al vroeg prestatieproblemen ondervinden (u ziet bijvoorbeeld dat een deel van uw app traag wordt uitgevoerd) en u moet uw app mogelijk vroeg testen met de profileringshulpprogramma's. Zie Bekijk eerst de hulpprogramma's voor profileringvoor meer informatie over profileringsprogramma's zoals het hulpprogramma CPU-gebruik en de Memory Analyzer.
Verwante inhoud
In dit artikel hebt u geleerd hoe u veel veelvoorkomende fouten in uw code kunt voorkomen en oplossen en wanneer u het foutopsporingsprogramma gebruikt. Lees vervolgens meer over het gebruik van het Visual Studio-foutopsporingsprogramma om fouten op te lossen.