Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
La résolution des bogues et des erreurs dans votre code peut être une tâche fastidieuse et parfois frustrante. Il faut du temps pour apprendre à déboguer efficacement. Un IDE puissant comme Visual Studio peut faciliter votre travail. Un IDE peut vous aider à corriger les erreurs et à déboguer votre code plus rapidement et à écrire un meilleur code avec moins de bogues. Cet article fournit une vue holistique du processus de « correction de bogues », afin de savoir quand utiliser l’analyseur de code, quand utiliser le débogueur, comment corriger les exceptions et comment coder pour l’intention. Si vous savez déjà que vous devez utiliser le débogueur, consultez d’abord le débogueur.
Dans cet article, vous allez apprendre à utiliser l’IDE pour rendre vos sessions de codage plus productives. Nous abordons plusieurs tâches, telles que :
Préparer votre code pour le débogage à l’aide de l’analyseur de code de l’IDE
Résolution des exceptions (erreurs d’exécution)
Comment réduire les bogues en programmant en fonction de l'intention (à l’aide de l’assertion)
Quand utiliser le débogueur
Pour illustrer ces tâches, nous affichons quelques-uns des types d’erreurs et de bogues les plus courants que vous pouvez rencontrer lors de la tentative de débogage de vos applications. Bien que l’exemple de code soit C#, les informations conceptuelles s’appliquent généralement à C++, Visual Basic, JavaScript et d’autres langages pris en charge par Visual Studio (sauf indication contraire). Les captures d’écran sont en C#.
Créer un exemple d’application avec des bogues et des erreurs dans celui-ci
Le code suivant contient quelques bogues que vous pouvez corriger à l’aide de l’IDE Visual Studio. Cette application est une application simple qui simule l’obtention de données JSON à partir d’une opération, désérialisant les données vers un objet et mettant à jour une liste simple avec les nouvelles données.
Pour créer l’application, visual Studio doit être installé et la charge de travail de développement de bureau .NET doit être installée.
Si vous n’avez pas encore installé Visual Studio, allez sur la page des téléchargements de Visual Studio pour l’installer gratuitement.
Si vous avez besoin d'installer la charge de travail mais que vous avez déjà Visual Studio, sélectionnez Outils>Obtenir des outils et des fonctionnalités. Le programme d’installation de Visual Studio démarre. Choisissez la charge de travail Développement .NET Desktop, puis choisissez Modifier.
Procédez comme suit pour créer l’application :
Ouvrez Visual Studio. Dans la fenêtre de démarrage, sélectionnezCréer un projet.
Dans la zone de recherche, entrez la console , puis l’une des options de l’application console pour .NET.
Cliquez sur Suivant.
Entrez un nom de projet tel que Console_Parse_JSON, puis sélectionnez Suivant ou Créer, le cas échéant.
Choisissez l’infrastructure cible recommandée ou .NET 8, puis sélectionnez Créer.
Si vous ne voyez pas le modèle de projet Application console pour .NET, accédez à Outils>Obtenir des outils et fonctionnalités, ce qui ouvre l'installeur de Visual Studio. Choisissez la charge de travail Développement .NET Desktop, puis choisissez Modifier.
Visual Studio crée le projet de console, qui apparaît dans l’Explorateur de solutions dans le volet droit.
Lorsque le projet est prêt, remplacez le code par défaut dans le fichier Program.cs du projet par l’exemple de code suivant :
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;
}
}
Trouvez les écumes rouges et verts !
Avant d’essayer de démarrer l’application exemple et d’exécuter le débogueur, vérifiez le code dans l’éditeur de code pour les soulignements rouges et verts. Celles-ci représentent des erreurs et des avertissements identifiés par l’analyseur de code de l’IDE. Les gouilles rouges sont des erreurs au moment de la compilation, que vous devez corriger avant de pouvoir exécuter le code. Les écumes verts sont des avertissements. Bien que vous puissiez souvent exécuter votre application sans corriger les avertissements, ils peuvent être une source de bogues et vous vous économisez souvent du temps et des problèmes en les examinant. Ces avertissements et erreurs s’affichent également dans la fenêtre Liste d’erreurs , si vous préférez un affichage de liste.
Dans l'exemple de l'application, vous voyez plusieurs zigzags rouges que vous devez corriger et un zigzag vert que vous devez examiner. Voici la première erreur.
Pour corriger cette erreur, vous pouvez examiner une autre fonctionnalité de l’IDE, représentée par l’icône d’ampoule.
Vérifiez l’ampoule !
La première bascule rouge représente une erreur au moment de la compilation. Pointez dessus et le message The name `Encoding` does not exist in the current contexts’affiche.
Notez que cette erreur affiche une icône d’ampoule en bas à gauche. En plus de
,
représente des actions rapides qui peuvent vous aider à corriger ou refactoriser le code en ligne. L’ampoule représente des problèmes que vous devez résoudre. Le tournevis est destiné aux problèmes que vous pouvez choisir de corriger. Utilisez le premier correctif suggéré pour résoudre cette erreur en cliquant sur System.Text sur la gauche.
Lorsque vous sélectionnez cet élément, Visual Studio ajoute l'instruction using System.Text en haut du fichier Program.cs, et le soulignement rouge disparaît. (Lorsque vous n’êtes pas sûr des modifications appliquées par un correctif suggéré, choisissez le lien Aperçu des modifications à droite avant d’appliquer le correctif.)
L’erreur précédente est une erreur courante que vous corrigez généralement en ajoutant une nouvelle using instruction à votre code. Il existe plusieurs erreurs courantes, similaires à celle-ci, telles que The type or namespace "Name" cannot be found. ces types d’erreurs peuvent indiquer une référence d’assembly manquante (cliquez avec le bouton droit sur le projet, choisissez Ajouter> uneréférence), un nom mal orthographié ou une bibliothèque manquante que vous devez ajouter (pour C#, cliquez avec le bouton droit sur le projet et choisissez Gérer les packages NuGet).
Corriger les erreurs et avertissements restants
Il y a quelques zigzags supplémentaires à analyser dans ce code. Ici, vous voyez une erreur de conversion de type courante. Lorsque vous pointez sur le bouton bascule, vous voyez que le code tente de convertir une chaîne en int, ce qui n’est pas pris en charge, sauf si vous ajoutez du code explicite pour effectuer la conversion.
Étant donné que l’analyseur de code ne peut pas deviner votre intention, il n’y a pas d’ampoules pour vous aider cette fois. Pour corriger cette erreur, vous devez connaître l’intention du code. Dans cet exemple, il n’est pas trop difficile de voir qu’il points doit s’agir d’une valeur numérique (entier), car vous essayez d’ajouter points à totalpoints.
Pour corriger cette erreur, modifiez le points membre de la User classe à partir de ceci :
[DataMember]
internal string points;
à ceci :
[DataMember]
internal int points;
Les lignes rouges ondulées dans l'éditeur de code disparaissent.
Placez ensuite le curseur sur le soulignement vert dans la déclaration du points membre de donnée. L’analyseur de code vous indique que la variable n’est jamais affectée à une valeur.
En règle générale, cela représente un problème qui doit être résolu. Toutefois, dans l'application d'exemple, vous stockez des données dans la variable points pendant le processus de désérialisation, puis ajoutez cette valeur au membre de données totalpoints. Dans cet exemple, vous connaissez l’intention du code et pouvez ignorer en toute sécurité l’avertissement. Toutefois, si vous souhaitez éliminer l’avertissement, vous pouvez remplacer le code suivant :
item.totalpoints = users[i].points;
avec ceci :
item.points = users[i].points;
item.totalpoints += users[i].points;
Le gêle vert disparaît.
Corriger une exception
Lorsque vous avez corrigé tous les soulignements rouges ondulés et résolu, ou au moins investigué, tous les soulignements verts ondulés, vous êtes prêt à lancer le débogueur et l'application.
Appuyez sur
À ce stade, l’exemple d’application lève une SerializationException exception (erreur d’exécution). Autrement dit, l’application a du mal à traiter les données qu’elle essaie de sérialiser. Étant donné que vous avez démarré l’application en mode débogage (débogueur attaché), l’assistance d’exception du débogueur vous permet d’accéder au code qui a levé l’exception et vous donne un message d’erreur utile.
Le message d’erreur vous indique que la valeur 4o ne peut pas être analysée en tant qu’entier. Par conséquent, dans cet exemple, vous savez que les données sont incorrectes : 4o doit être 40. Toutefois, si vous n’êtes pas en contrôle des données dans un scénario réel (supposons que vous l’obtenez à partir d’un service web), que faites-vous à ce sujet ? Comment résoudre ce problème ?
Lorsque vous rencontrez une exception, vous devez poser (et répondre) quelques questions :
Cette exception n’est-elle qu’un bogue que vous pouvez corriger ? Ou,
Cette exception peut-elle être rencontrée par vos utilisateurs ?
S’il s’agit de l’ancien, corrigez le bogue. (Dans l’exemple d’application, vous devez corriger les données incorrectes.) S’il s’agit de ce dernier, vous devrez peut-être gérer l’exception dans votre code à l’aide d’un try/catch bloc (nous examinons d’autres stratégies possibles dans la section suivante). Dans l’exemple d’application, remplacez le code suivant :
users = ser.ReadObject(ms) as User[];
avec ce 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
}
Un try/catch bloc a des coûts de performances. Vous ne voudrez donc les utiliser que lorsque vous en avez vraiment besoin, c’est-à-dire où (a) ils peuvent se produire dans la version de publication de l’application, et où (b) la documentation de la méthode indique que vous devez vérifier l’exception (en supposant que la documentation est terminée !). Dans de nombreux cas, vous pouvez gérer une exception de manière appropriée et l’utilisateur n’aura jamais besoin de le savoir.
Voici quelques conseils importants pour la gestion des exceptions :
Évitez d’utiliser un bloc catch vide, par exemple
catch (Exception) {}, qui n’effectue pas d’action appropriée pour exposer ou gérer une erreur. Un bloc catch vide ou nonformatif peut masquer les exceptions et rendre votre code plus difficile à déboguer au lieu de faciliter le débogage.Utilisez le
try/catchbloc autour de la fonction spécifique qui lève l’exception (ReadObjectdans l’exemple d’application). Si vous l’utilisez autour d’un bloc de code plus volumineux, vous masquez l’emplacement de l’erreur. Par exemple, n’utilisez pas letry/catchbloc autour de l’appel à la fonction parenteReadToObject, affichée ici, sinon vous ne saurez pas exactement où l’exception s’est produite.// Don't do this try { User[] users = ReadToObject(data); } catch (SerializationException) { }Pour les fonctions inconnues que vous incluez dans votre application, en particulier les fonctions qui interagissent avec des données externes (telles qu’une demande web), consultez la documentation pour voir quelles exceptions la fonction est susceptible de lever. Il peut s’agir d’informations critiques pour la gestion des erreurs appropriée et pour le débogage de votre application.
Pour l'application d'exemple, corrigez la SerializationException dans la méthode GetJsonData en remplaçant 4o par 40.
Conseil / Astuce
Si vous avez Copilot, vous pouvez obtenir une assistance de l'intelligence artificielle pendant le débogage des exceptions. Recherchez simplement le bouton Demander à Copilot
. Pour plus d’informations, consultez Déboguer avec Copilot.
Clarifier votre intention de code à l’aide de l’assertion
Sélectionnez le bouton Redémarrer
dans la barre d'outils de débogage (Ctrl + Maj + F5). Cela redémarre l’application en moins d’étapes. Vous voyez la sortie suivante dans la fenêtre de console.
Vous pouvez voir que quelque chose ne va pas dans cette sortie. Les valeurs de prénom et de nom du troisième enregistrement sont vides !
C’est un bon moment pour parler d’une pratique de codage utile, souvent sous-utilisée, qui consiste à utiliser assert des instructions dans vos fonctions. En ajoutant le code suivant, vous incluez une vérification à l'exécution pour vous assurer que firstname et lastname ne sont pas null. Remplacez le code suivant dans la UpdateRecords méthode :
if (existingUser == false)
{
User user = new User();
user.firstname = users[i].firstname;
user.lastname = users[i].lastname;
avec ceci :
// 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;
En ajoutant des assert instructions comme celles-ci à vos fonctions pendant le processus de développement, vous pouvez vous aider à spécifier l’intention de votre code. Dans l’exemple précédent, nous spécifions les éléments suivants :
- Une chaîne valide est requise pour le prénom
- Une chaîne valide est requise pour le nom de famille
En spécifiant l’intention de cette façon, vous appliquez vos exigences. Il s’agit d’une méthode simple et pratique que vous pouvez utiliser pour exposer des bogues pendant le développement. ( lesassert instructions sont également utilisées comme élément principal dans les tests unitaires.)
Sélectionnez le bouton Redémarrer
dans la barre d'outils de débogage (Ctrl + Maj + F5).
Note
Le assert code est actif uniquement dans une compilation de débogage.
Lorsque vous redémarrez, le débogueur s’interrompt sur l’instruction assert, car l’expression users[i].firstname != null s'évalue à false au lieu de true.
L’erreur assert vous indique qu’il existe un problème que vous devez examiner.
assert peut couvrir de nombreux scénarios où vous ne voyez pas nécessairement d’exception. Dans cet exemple, l’utilisateur ne voit pas d’exception et une null valeur est ajoutée comme firstname dans votre liste d’enregistrements. Cette condition peut entraîner des problèmes plus tard (par exemple, dans la sortie de la console) et peut être plus difficile à déboguer.
Note
Dans les scénarios où vous appelez une méthode sur la null valeur, un NullReferenceException se produit. Vous souhaitez normalement éviter d’utiliser un try/catch bloc pour une exception générale, c’est-à-dire une exception qui n’est pas liée à la fonction de bibliothèque spécifique. N’importe quel objet peut lever un NullReferenceException. Vérifiez la documentation de la fonction de bibliothèque si vous n’êtes pas sûr.
Pendant le processus de débogage, il est préférable de conserver une instruction particulière assert jusqu’à ce que vous sachiez que vous devez la remplacer par un correctif de code réel. Supposons que vous décidiez que l’utilisateur pourrait rencontrer l’exception dans une version de production de l’application. Dans ce cas, vous devez refactoriser le code pour vous assurer que votre application ne lève pas d’exception irrécupérable ou génère une autre erreur. Par conséquent, pour corriger ce code, remplacez le code suivant :
if (existingUser == false)
{
User user = new User();
avec ce code :
if (existingUser == false && users[i].firstname != null && users[i].lastname != null)
{
User user = new User();
Avec ce code, vous satisfaites vos exigences en matière de code et vous assurez qu’un enregistrement avec une valeur de firstname ou lastname de null n’est pas ajouté aux données.
Dans cet exemple, nous avons ajouté les deux assert instructions à l’intérieur d’une boucle. En règle générale, lors de l’utilisation assert, il est préférable d’ajouter assert des instructions au point d’entrée (début) d’une fonction ou d’une méthode. Vous examinez actuellement la UpdateRecords méthode dans l’exemple d’application. Dans cette méthode, vous savez que vous rencontrez des problèmes si l’un des arguments de méthode est null, vérifiez-les à la fois avec une assert instruction au point d’entrée de la fonction.
public static void UpdateRecords(List<User> db, User[] users)
{
Debug.Assert(db != null);
Debug.Assert(users != null);
Pour les instructions précédentes, votre intention est de charger des données existantes (db) et de récupérer de nouvelles données (users) avant de mettre à jour quoi que ce soit.
Vous pouvez utiliser assert avec n’importe quel type d’expression qui se résout à true ou false. Par exemple, vous pouvez ajouter une assert instruction comme celle-ci.
Debug.Assert(users[0].points > 0);
Le code précédent est utile si vous souhaitez spécifier l’intention suivante : une nouvelle valeur de point supérieure à zéro (0) est requise pour mettre à jour l’enregistrement de l’utilisateur.
Inspecter votre code dans le débogueur
OK, maintenant que vous avez résolu tout ce qui est critique avec l’exemple d’application, vous pouvez passer à d’autres éléments importants !
Nous vous avons montré l’assistance sur l’exception du débogueur, mais le débogueur est un outil beaucoup plus puissant qui vous permet également d’effectuer d’autres opérations telles que parcourir votre code et inspecter ses variables. Ces fonctionnalités plus puissantes sont utiles dans de nombreux scénarios, en particulier les scénarios suivants :
Vous essayez d’isoler un bogue d’exécution dans votre code, mais ne pouvez pas le faire à l’aide de méthodes et d’outils précédemment abordés.
Vous souhaitez valider votre code, c’est-à-dire le regarder pendant qu’il s’exécute pour vous assurer qu’il se comporte de la façon dont vous vous attendez et que vous le souhaitez.
Il est instructif de regarder votre code pendant qu’il s’exécute. Vous pouvez en savoir plus sur votre code de cette façon et peut souvent identifier les bogues avant qu’ils ne manifestent des symptômes évidents.
Pour savoir comment utiliser les fonctionnalités essentielles du débogueur, consultez Débogage pour les débutants absolus.
Résoudre des problèmes de performance
Les bogues d’un autre type incluent du code inefficace qui entraîne l’exécution lente de votre application ou l’utilisation d’une mémoire trop importante. En règle générale, l’optimisation des performances est quelque chose que vous effectuez ultérieurement dans votre développement d’applications. Toutefois, vous pouvez rencontrer des problèmes de performances précoces (par exemple, vous voyez que certaines parties de votre application s’exécutent lentement) et que vous devrez peut-être tester votre application avec les outils de profilage au début. Pour plus d’informations sur les outils de profilage tels que l’outil Utilisation du processeur et l’analyseur de mémoire, consultez Premier aperçu des outils de profilage.
Contenu connexe
Dans cet article, vous avez appris à éviter et à corriger de nombreux bogues courants dans votre code et quand utiliser le débogueur. Ensuite, apprenez-en davantage sur l’utilisation du débogueur Visual Studio pour corriger les bogues.