Méthodes conseillées pour la gestion des exceptions
Un jeu de blocs de code de gestion d'erreurs correctement conçu peut rendre un programme plus robuste et moins enclin aux blocages dus à la gestion de ces erreurs par l'application. La liste suivante contient des suggestions relatives aux méthodes conseillées pour la gestion des exceptions :
Déterminez quand vous devez définir un bloc try/catch. Par exemple, vous pouvez vérifier par programme la présence d'une condition qui risque probablement de se produire sans le recours à la gestion des exceptions. Dans d'autres situations, l'utilisation de la gestion des exceptions pour intercepter un cas d'erreur est appropriée.
L'exemple suivant utilise une instruction if pour déterminer si une connexion est fermée. Vous pouvez utiliser cette méthode au lieu de lever une exception si la connexion n'est pas fermée.
If conn.State <> ConnectionState.Closed Then conn.Close() End If if(conn.State != ConnectionState.Closed) conn.Close();
Dans l'exemple suivant, une exception est levée si la connexion n'est pas fermée.
Try conn.Close() Catch ex As InvalidOperationException 'Do something with the error or ignore it. End Try try { conn.Close(); } catch(InvalidOperationException ex) { //Do something with the error or ignore it. }
La méthode que vous choisissez dépend de la fréquence à laquelle l'événement se produit. Si l'événement est véritablement exceptionnel et constitue une erreur (par exemple une fin de fichier inattendue), l'utilisation de la gestion des exceptions est plus indiquée car la quantité de code exécutée en situation normale est moindre. Si l'événement se produit régulièrement, l'utilisation de la méthode par programmation pour rechercher les erreurs est plus appropriée. En ce cas, si une exception se produit, la gestion de l'exception prendra plus de temps.
Utilisez des blocs try/finally autour du code pouvant potentiellement générer une exception et centralisez vos instructions catch en un point unique. De cette façon, l'instruction try génère l'exception, l'instruction finally ferme ou libère des ressources et l'instruction catch gère l'exception à partir d'un point central.
Veillez à toujours classer les exceptions dans les blocs catch de la plus spécifique à la moins spécifique. Cette technique permet de gérer l'exception spécifique avant qu'elle ne passe à un bloc catch plus général.
Terminez les noms de classe d'exception par le mot « Exception ». Par exemple :
Public Class EmployeeListNotFoundException Inherits Exception public class MyFileNotFoundException : Exception { }
Lors de la création d'exceptions définies par l'utilisateur, vous devez vous assurer que les métadonnées des exceptions sont disponibles pour le code s'exécutant à distance, y compris lorsque des exceptions se produisent à travers des domaines d'application. Par exemple, supposons que le domaine d'application A crée le domaine d'application B, lequel exécute le code qui lève une exception. Pour que le domaine d'application A intercepte et gère correctement l'exception, il doit pouvoir trouver l'assembly contenant l'exception levée par le domaine d'application B. Si le domaine d'application B lève une exception qui est contenue dans un assembly sous sa base d'application, mais pas sous la base d'application du domaine d'application A, ce dernier ne peut pas trouver l'exception et le Common Language Runtime lève FileNotFoundException. Pour éviter cette situation, vous pouvez déployer l'assembly contenant les informations sur les exceptions de deux façons :
placez l'assembly dans une base d'application commune partagée par les deux domaines d'application
- ou -
si les domaines ne partagent pas une base d'application commune, signez l'assembly contenant les informations sur les exceptions à l'aide d'un nom fort et déployez l'assembly dans le Global Assembly Cache.
En C# et C++, utilisez au moins les trois constructeurs communs lors de la création de vos propres classes d'exception. Pour obtenir un exemple, consultez Utilisation d'exceptions définies par l'utilisateur.
Dans la plupart des cas, utilisez les types d'exceptions prédéfinis. Définissez de nouveaux types d'exceptions pour des scénarios par programmation. Introduisez une nouvelle classe d'exceptions afin de permettre au programmeur d'exécuter une action différente basée sur la classe d'exceptions.
Pour la plupart des applications, dérivez des exceptions personnalisées à partir de la classe Exception. À l'origine, il était prévu que les exceptions personnalisées devraient dériver de la classe ApplicationException ; toutefois, en pratique, il s'est avéré que cette méthode n'apportait pas beaucoup d'avantages.
Insérez une chaîne de description localisée dans chaque exception. Quand l'utilisateur voit un message d'erreur, celui-ci est dérivé non pas de la classe d'exceptions mais de la chaîne de description de l'exception qui a été levée.
Créez des messages d'erreur corrects du point de vue de la syntaxe, y compris la ponctuation de fin. Chaque phrase de la chaîne de description d'une exception doit se terminer par un point.
Fournissez des propriétés Exception pour l'accès par programme. Incluez des informations supplémentaires (autres que la chaîne de description) dans une exception uniquement s'il existe un scénario par programme dans lequel les informations supplémentaires sont utiles.
Retournez null pour les cas d'erreur très répandus. Par exemple, une commande File.Open retourne null si le fichier est introuvable mais lève une exception si le fichier est verrouillé.
Créez des classes de façon qu'une exception ne soit jamais levée en usage normal. Par exemple, une classe FileStream expose une autre manière de déterminer si la fin d'un fichier a été atteinte. Vous évitez ainsi l'exception qui est levée si vous dépassez la fin du fichier pendant la lecture. L'exemple suivant montre comment lire le fichier jusqu'à la fin.
Class FileRead Sub Open() Dim stream As FileStream = _ File.Open("myfile.txt", FileMode.Open) Dim b As Byte Dim result As Integer ' ReadByte returns -1 at EOF. Do result = stream.ReadByte() If result = -1 Then Exit Do b = CByte(result) ' Do something. Loop ' Call stream.Close() here or in another method. End Sub 'Open End Class 'FileRead class FileRead { public void Open() { FileStream stream = File.Open("myfile.txt", FileMode.Open); byte b; int result; // ReadByte returns -1 at EOF. while ((result = stream.ReadByte()) != -1) { b = (byte)result; // Do something. } // Call stream.Close() here or in another method. } }
Levez une exception InvalidOperationException si un appel de jeu de propriétés ou de méthode n'est pas approprié étant donné l'état actuel de l'objet.
Levez ArgumentException ou une classe dérivée de ArgumentException si des paramètres incorrects sont passés.
La trace de la pile commence à l'instruction où l'exception est levée et se termine à l'instruction catch qui intercepte l'exception. N'oubliez pas ce fait au moment de déterminer l'endroit auquel vous devez placer une instruction throw.
Utilisez des méthodes de générateur d'exceptions. Il est fréquent qu'une classe lève la même exception à partir de différents endroits de son implémentation. Pour éviter un excès de code, utilisez des méthodes d'assistance qui créent une exception et la retournent. Par exemple :
Class File Private fileName As String Public Function Read(bytes As Integer) As Byte() If Not ReadFile(handle, bytes) Then Throw NewFileIOException() End If End Function 'Read Function NewFileIOException() As FileException Dim description As String = __unknown ' Build localized string, including fileName. Return New FileException(description) ' End Function 'NewFileIOException End Class 'File class File { string fileName; public byte[] Read(int bytes) { if (!ReadFile(handle, bytes)) throw NewFileIOException(); } FileException NewFileIOException() { string description = // Build localized string, including fileName. return new FileException(description); } }
Dans les autres cas, utilisez le constructeur d'exception pour générer l'exception. Cette approche est plus appropriée pour les classes d'exceptions globales, telles que ArgumentException.
Levez des exceptions au lieu de retourner un code d'erreur ou HRESULT.
Supprimez les résultats intermédiaires lorsque vous levez une exception. Les appelants doivent supposer qu'il n'y a aucun effet secondaire quand une exception est levée à partir d'une méthode.