Après avoir lu mon "Comment séparer le code d'interface et le code fonctionnel (basé sur Delphi/VCL)", quelqu'un a mentionné une question sur la façon de gérer les erreurs dans les classes côté serveur.
Dans les structures basées sur des fonctions, nous utilisons généralement les valeurs de retour de fonction pour indiquer si la fonction a été exécutée avec succès et pour donner des informations telles que les types d'erreurs. On aura donc du code sous la forme suivante :
RetVal := SomeFunctionToOpenFile();
si RetVal = E_SUCCESSED alors
...
sinon si RetVal = E_FILENOTFOUND alors
...
sinon si RetVal = E_FILEFORMATERR alors
...
sinon alors
...
Il est très courant d'utiliser une méthode qui renvoie un code d'erreur, mais l'utilisation d'une telle méthode pose deux problèmes :
1. Cela crée une structure de branches longue et compliquée (un grand nombre d’instructions if ou case), ce qui rend le processus de contrôle compliqué.
2. Il peut y avoir des erreurs qui n'ont pas été traitées (si l'appelant de la fonction ne détermine pas la valeur de retour)
Les exceptions sont une solution orientée objet pour la gestion des erreurs. Il peut signaler des erreurs, mais ce que vous devez savoir, c'est que l'exception n'est pas déclenchée à cause de l'erreur, mais simplement parce que raise est utilisé.
En Pascal Objet, le mot réservé surélevé est utilisé pour lever des exceptions. À tout moment (même si aucune erreur ne se produit), raise provoquera une exception.
Les exceptions peuvent entraîner le retour immédiat du code à partir du point où l'exception se produit, protégeant ainsi le code sensible ci-dessous de l'exécution. Il n'y a aucune différence entre le retour d'une fonction via une exception et le retour d'une fonction normalement (exécution jusqu'à la fin de la fonction ou exécution de Exit) pour la fonction elle-même qui lève l'exception. La différence est que du côté de l'appelant, après le retour d'une exception, les droits d'exécution seront capturés par le try...sauf les blocs (s'ils existent). S'il n'y a pas de bloc try...sauf chez l'appelant, les instructions suivantes ne continueront pas à être exécutées, mais reviendront à l'appelant de niveau supérieur jusqu'à ce qu'un bloc try...sauf capable de gérer l'exception soit trouvé. Une fois l'exception gérée, les instructions après le bloc try...sauf continueront à être exécutées et le contrôle sera laissé dans la couche qui gère l'exception. Lorsque le gestionnaire d'exceptions estime que la gestion de l'exception n'est pas suffisamment complète, il a besoin que l'appelant de niveau supérieur continue le traitement. Il peut relancer l'exception (en utilisant une simple augmentation ;) et transférer le contrôle à l'appelant de niveau supérieur. .
S'il n'y a aucun préréglage try...sauf bloc, l'exception finale sera interceptée par le bloc try...sauf le plus externe de la VCL qui encapsule l'intégralité du programme.
Par conséquent, il n’y aura pas d’exceptions non gérées, en d’autres termes, il n’y aura pas d’erreurs non gérées (bien que les erreurs et les exceptions ne soient pas assimilées). C'est également l'avantage du mécanisme d'exception par rapport à l'utilisation de méthodes qui renvoient des codes d'erreur. De plus, une fois l'exception levée, la direction du processus de contrôle est très claire et ne fera pas perdre le contrôle du processus.
Pour donner un exemple du fonctionnement des exceptions, supposons que nous souhaitions ouvrir un fichier dans un format spécifique :
Définissez d’abord deux classes d’exception (héritées de Exception)
EFileNotFound = classe (Exception);
EFileFormatErr = classe (Exception);
Supposons qu'il y ait un bouton sur Form1 et qu'appuyer sur ce bouton ouvre le fichier :
PRécédure TForm1.Button1Click(Expéditeur : TObject);
commencer
essayer
ToOpenFile();
sauf
sur EFileNotFound faire
ShowMessage('Désolé, je ne trouve pas le fichier');
onEFileFormatErr faire
ShowMessage('Désolé, le fichier n'est pas celui que je veux');
sur E:Exception faire
ShowMessage(E.Message);
fin;
fin;
Et la fonction pour ouvrir le fichier :
procédure ToOpenFile ;
varRetVal : Entier ;
commencer
// Du code pour ouvrir le fichier
RetVal := -1; //échec de l'ouverture
si RetVal = 0 alors //succès
Sortie
sinon si RetVal = -1 alors
Augmenter EFileNotFound.Create('Fichier introuvable')
sinon si RetVal = -2 alors
Augmenter EFileFormatErr.Create('Erreur de format de fichier')
sinon //autre erreur
Raise Exception.Create('Erreur inconnue');
fin;
Dans le programme, TForm1.Button1Click appelle ToOpenFile et prédéfinit try...sauf pour la gestion des exceptions qui peuvent être levées par ToOpenFile. Bien entendu, le code de gestion des exceptions de TForm1.Button1Click peut également être simplifié :
procédure TForm1.Button1Click(Expéditeur : TObject);
commencer
essayer
ToOpenFile();
sauf
ShowMessage('Échec de l'ouverture du fichier');
fin;
fin;
L'utilisation d'exceptions résout les problèmes liés à l'utilisation de méthodes qui renvoient des codes d'erreur. Bien entendu, l'utilisation d'exceptions n'est pas gratuite. Les exceptions augmenteront la charge du programme, il n’est donc pas conseillé d’en abuser. Il y a une grande différence entre écrire quelques essais...sauf et écrire des milliers d'essais...sauf. Selon les mots de Charlie Calverts : "Vous devriez utiliser try...sauf les blocages lorsque cela semble utile. Mais essayez de ne pas trop vous enthousiasmer pour cette technique."
De plus, Object Pascal introduit une structure try...finally unique. J'ai déjà dit qu'il n'y avait aucune différence entre revenir d'une fonction via une exception et revenir d'une fonction normalement. Par conséquent, les objets locaux de la pile dans la fonction seront automatiquement libérés, mais pas les objets du tas. Cependant, le modèle objet d'Object Pascal est basé sur des références qui existent dans le tas et non dans la pile. Par conséquent, nous devons parfois nettoyer certaines ressources d'objets locaux avant de revenir d'une fonction via une exception. essayez... résout enfin ce problème.
J'ai réécrit le code ToOpenFile ci-dessus, cette fois en utilisant certaines ressources pendant le processus ToOpenFile, et en libérant ces ressources après que l'exception se soit produite (ou ne se produit pas) avant de revenir de la fonction :
procédure ToOpenFile ;
varRetVal : entier ;
Flux : TStream ;
commencer
// Du code pour ouvrir le fichier
Stream := TStream.Create;
RetVal := -1; //échec de l'ouverture
essayer
si RetVal = 0 alors //succès
Sortie
sinon si RetVal = -1 alors
Augmenter EFileNotFound.Create('Fichier introuvable')
sinon si RetVal = -2 alors
Augmenter EFileFormatErr.Create('Erreur de format de fichier')
sinon //autre erreur
Raise Exception.Create('Erreur inconnue');
enfin
Stream.Gratuit ;
fin;
fin;
En parcourant le code ci-dessus, nous pouvons voir que même lorsque la valeur de RetVal est 0, après l'exécution de Exit, le code final sera toujours exécuté puis reviendra de la fonction. Cela garantit la libération correcte des ressources locales.
Les objectifs et les scénarios d'utilisation de try...sauf et try...finally sont différents et de nombreux débutants les confondent. Ce qui suit est une connaissance personnelle de l'auteur : try...sauf est généralement utilisé par l'appelant pour capturer les exceptions levées par les fonctions appelées et les gérer. Et try...finally est généralement utilisé pour la fonction qui lève l'exception afin d'effectuer un travail de nettoyage des ressources.
La programmation orientée objet fournit une solution de gestion des erreurs appelée « exception ». Utilisé à bon escient, il profitera à notre travail et pourra améliorer considérablement la qualité du code que nous écrivons.
Nicrosoft ([email protected]) 2001.7.25
Source originale : Document Sunistudio (http://www.sunistudio.com/asp/sunidoc.asp)