begin process at 2012 02 16 08:15:30
  Trouver un code source :
 
dans
 
Accueil > 

Tutoriels

 > 

Optimisation du code

 > ERREUR SANS DOULEURS...

ERREUR SANS DOULEURS...


 Information sur le tutoriel

Note :
8 / 10 - par 4 personnes
8,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

 Description

Ce tutoriel va vous montrer comment structurer votre manipulation d'erreur jusqu'à rendre votre application vraiment fiable.

Tutorial

ERREURS SANS DOULEURS...

La manipulation d'erreur de VB est déficiente (mais elle existe) parce que trop simpliste et sans structure.

Ce tutoriel va vous montrer comment structurer votre manipulation d'erreur jusqu'à rendre votre application
vraiment fiable.

MODELE

La manipulation d'erreur de Java (et de C#, VB.Fred et autres) est la suivante:

try{
    code risqué}
catch (typeErreur = spécifique){
    récupération de cette erreur}
catch (typeErreur = générale){
    récupération de l'erreur plus lourde}
finally{
    allez, on essuie tout ou s'il n'y a pas eu d'erreur, on nettoie quand même}


Je vais essayer de structurer une manipulation d'erreur approchant ce modèle.

EXAMPLE A NE PAS SUIVRE

Ce code fictif ne montre que la manipulation, déficiente parce que suivre ce code est difficile et cette difficulté n'est pas nécessaire. Ce code oblige le programmeur à tricoter dans le code et souvent il doit deviner le pourquoi du Resume Next

On Error GoTo label_1
Open DocAbsent for Binary as #number
Open DocAbsent2 for Binary as #number2
...
label_1:
MsgBox "Document n'existe pas...", vbOkOnly,"Crétin"
Resume next
End Function


AUTRE MAUVAIS EXAMPLE

On Error Resume Next
... 'ignorons ici toutes les préventions possible qu'on peut y mettre. Ce n'est pas encore le but.
CommonDialog1.CancelError = True
CommonDialog1.ShowOpen
FaireManip CommonDialog1.Filename


...que se passe-t-il si l'usager cancelle ? Est-ce que "FaireManip" maniera l'erreur ?

COMMENT SELECTIONNER UNE METHODE SIMPLE

LABEL

L'utilisation d'un label de renvoi d'erreur est à prévoir s'il y a un gros bloc de code entre le début de
l'opération risquée et sa fin et s'il n'y as pas d'autre opération risquée après le label.
Si c'est le cas, la fonction est tros longue et doit être normalisée (répartie) en plusieurs fonctions distinctes.
Dans tous les cas, si la fonction appelante doit tenir compte des erreurs, faire suivre la valeur.

Ex.:
Public Function Appelée() as Long
On Error GoTo label2
Call FonctionQuiPlante
....
Exit function
label2:

' Si nécessaire quelque code de nettoyage
Call RamasseToi
Appelée = Err.Number
End Function


Pourquoi faire suivre le numéro d'erreur ? Parce qu'en VB, toute erreur déclarée et maniée localement reste locale tout comme une variable locale. S'il y a erreur, la fonction appelante n'en saura rien à moins qu'on lui dise.
Je sais que la commande Err.Raise Err.Number pourrait être utilisée mais je répugne à l'utiliser, étant super
habitué à l'autre méthode.

ON ERROR RESUME NEXT

De nombreux programmeurs décrient cette méthode et avec raison car trop souvent, un paresseux s'en sert pour
ignorer l'erreur en espérant que ses effets peuvent être ignorés plus tard.
Mais bien planifiée, elle permet un réel controle du cheminement des opérations.

Ex.: CommonDialog sécurisé: méthode simple

Public Function GetFile(byval strDefaultFile as string) as string

    On Error Resume Next  'ligne nécessaire à cause de CancelError = True
    With CommonDialog1
        .Flags  = cdlOFNFileMustExist 
       ' l'usager est forcé de sélectionner un document existant
        .Filter ="Text (*.txt)|*.txt"        ' l'usager est forcé de sélectionner un doc 'txt'
        .FilterIndex = 1                '  ...et rien d'autre. noter l'extension est montrée à l'usager
        .Filename = strDefaultFile         ' Facultatif mais bon enfin...
        .DialogTitle = "Choisi, mec !"
        .CancelError = True            ' le coeur de l'affaire: en cas de cancel, une erreur est générée.
        .ShowOpen
    End With
    If Err.Number = 0 then 
               ' il n'y a qu'une erreur possible ici
        GetFile = CommonDialog1.FileName    ' passer le nom. Sinon, GetFile = ""
    End If    
End Function


Ex.: Manipulation plus complexe

....
On Error Resume Next
...
Set ExcelObject = GetObject(paramètres) ' Si Excel est déjà ouvert cette méthode le trouvera
' Sinon, deux facon de déceler l'erreur:
If ExcelObject Is Nothing then        ' mais cette méthode n'illustre pas l'example

If Err.Number <>0 then
    Err.Clear                    ' sinon la seconde partie sera déjà dans l'erreur
    Set ExcelObject = CreateObject(paramètres)
    If Err.Number <>0 then            ' capturer cette erreur nouvelle
        FunctionName = Err.Number    ' avertir la fonction appelante
        Exit Function            ' Err est locale ici donc nul besoin de faire un reset
    End If
    Err.Clear                    ' ici on continue

Ex.: Style Java

Dans ce dernier example, le code de la fonction doit ouvrir/créer un document binaire sans détruire un doc du même
nom préexistant. Certaines conditions (qui peuvent sembler factices (mais qui nous sont arrivées avec des clients
qui regardaient)) sont établies pour démontrer comment faire une cascade de manipulation.

Les codes d'erreur sont factices. Voir plus NOTE SUR CONSTANTES D'ERREUR plus bas.
Les erreurs ne sont pas maniées par les fonctions appelées, seulement capturées et renvoyées, comme ceci:

On Error Resume Next
If Err.Number <>0 then
    FunctionCalled = err.Number
    Exit Function
End If



If IsMediumPresent(Path) = err_NOMEDIUM then
    FunctionName = err_NOMEDIUM
    Exit Function

Else
    If IsMediumUnLocked(Path) = err_MEDIUMLOCKED then
        FunctionName = err_MEDIUMLOCKED
        Exit Function

    
    Else
        If IsMediumHasSpace(DocSize) = err_INSUFFICIENTSPACE then
            FunctionName = err_INSUFFICIENTSPACE
            Exit Function

        ' Si ces trois conditions sont satisfaites, le code continue après le block
        Endif
    End If
Endif


Maintenant continuons avec une autre approche

Err.Clear
On Error Resume Next
Select Case CreateDoc(strFilename)
    Case err_DOCEXIST

        ' demander un autre nom ou changer le nom du doc et informer l'usager
    Case err_DOCACCESSERROR
        ' le doc est ReadOnly: unlock ou informer l'usager
    Case err_DOCWRITEERROR
        ' Faut voir la cause exacte de l'erreur
    Case err_GENERICERROR
        ' alors la c'était vraiment pas prévu comme type d'erreur mais on reste dans le possible
    Case er_NOERROR
        ' mettre une continuation pour la function
        If WriteAllToDoc(strFilename) <> err_NOERROR Then GoTo label 'ici GoTo vaux la peine!

    Case Else
         ' ici c'est le délire...mais écrire dans un log d'erreur pourrait être une bonne idée.
          ' Charactères inconnus, valeurs invalide, ça peut être vraiment n'importe quoi.
End Select

......
label:

' réparation et controle des dommages

NOTE SUR CONSTANTES D'ERREUR

Par expérience, dès qu'une application dépasse une certaine masse de code, déboguer les erreurs devient très
difficile à suivre si les valeurs ne sont pas nommées d'une façon descriptive.
Pour faciliter le travail, regrouper toutes les erreurs possible à mesure que vous écrivez le code, en commencant
par la valeur de "pas d'erreur".
Ca donne quelque chose comme ceci.

Public Const err_NOERROR as Long = 0
Public Const err_DOCEXIST as Long = 64  
 ' rien n'interdit d'utiliser les codes d'erreur de VB
Public Const err_DOCACCESSERROR as Long = 98

Rien n'interdit d'avoir des valeurs doublées. L'mportant est d'avoir un nom pour la valeur.

Pour certaines fonction pouvant retourner des combinaisons de valeurs, utiliser des valeurs Hex comme ceci:

Public Const err_FlAGNONAME as Long= &H1
Public Const err_FlAGNOPASSWORD as Long= &H2
Public Const err_FlAGNOGROUP as Long= &H4
Public Const err_FlAGNOPERMISSION as Long= &H8

...et de suite
et les combiner en untilisant l'opérateur 'Or'

Un Long peut avoir 32 valeurs distinctes.

NOTRES EPARSES

La capture d'une erreur dans une structure If...ElseIf...Else...End If doit être regardée non seulement de façon à arrêter rapidement les opérations mais aussi à montrer qu'elles sont arrètées rapidement.

Une condition d'arrêt devrait être au début de la structure si des conditions complexes viennent après.
Ces conditions (il peut y en avoir plusieurs imbriquées) devraient être en tête de la structure.

Ex.:

If IsMediumUnLocked(docName)= False then
    ' erreur qui bloque tout
Else

    ' on continue
    ...
    ' D'autres conditions complexes suivent
End If

Cepandant si les conditions d'arrêts (même imbriquées) qui arrêtent tout ne sont pas suivies pas quoi que ce soitr d'autre, il est plus simple de sauter par dessus.

Ex.:

If DocExist(docName) = true then
    If DocNotLocked(docName) then

        ' faire la chose....
    End If
End If
' rien d'autre à faire

Bonne chance et ne succombez pas à l'erreur.  :-)

Commentaires

Commentaire de tof008 le 31/01/2007 16:00:04

trés beau tuto qui se peut se réveler trés utile, surtout qu'en général j'utilise les on error resume next et pas de la meilleure des manieres!
Bravo et merci

Commentaire de salim0shark le 20/04/2008 10:27:21

Bon tuto, pour gérer les erreurs en plus on sait tous que la force d'un programme qui tourne est la capacité de son créateur à gérer touts ses beugs
merci
salim0shark

Commentaire de Ouggada le 18/02/2009 10:56:22

La classe!!
Franchement bravo!!
c'est exactement ce que je cherchais!
je vais me coucher moins c... ce soir, c'est sûr!!!!

Commentaire de sugars le 17/07/2009 11:59:01

merci

Commentaire de Moktezuma le 18/07/2009 12:01:22

le Try / Catch a été ajouté à VB8, nan ?

Commentaire de bitshifter le 18/07/2009 14:22:36

Oui, MAIS...

VB.Fred est plus du Java que du Visual Basic Classique.

Personnellement, je préferais utiliser C#...ou du RealBasic.

Commentaire de bidouille007 le 03/10/2009 18:58:15

bonjour
Merci pour le tuto mais j'ai une erreur lors du débogage :
J'ai dans mes déclarations de variables ceci

    Public commandSQL As New OleDbCommand()

mais cela me génére l'erreur suivante :

Une exception de première chance de type 'System.NullReferenceException' s'est produite dans programme.exe

et je ne vois pas comment faire pour résoudre ce problème ?

Commentaire de bitshifter le 03/10/2009 19:14:56

Hélas, je ne peux t'aider.

A moins que...les parenthèses sont-elles nécessaires ?

Commentaire de bidouille007 le 03/10/2009 19:42:47

bitshifter merci pour cette suggestion c'est effectivement en supprimant les parenthèses au bout qui règle le problème.

Commentaire de 51M0N le 14/01/2010 10:09:26

Merci à vous BitShifter.
J'ai beau n'être qu'un néophyte, ce tutoriel m'est fort utile.

Commentaire de freyr86 le 30/06/2010 20:04:50

Bon j'ai pas bien compris la structure de la gestion des erreurs. Par contre pour le démarrage d'un application si le chemin d'accet est erronée je vous propose ce code dittent moi ce que vous en penser

On Error GoTo Erreur
'appele la gestion des tache windows
Dim varAppli As Long, varMess As Variant 'variable renvoyant un valeur 0 si le chemin est incorrect et variable MSGBOX
varAppli = Shell("C:\WINDOWS\system32\taskmgr.exe", vbNormalFocus)

Erreur:
If varAppli = 0 Then    'gestion de l'erreur
    'si le gestionnaire des taches n'est pas à l'endroit prevu
    varMess = MsgBox("Erreur d'accêt impossible d'afficher le gestionnaire des taches!!!", vbOKOnly + vbSystemModal + vbCritical, "Erreur")
End If


voila j'attand vos commentaires

Commentaire de bitshifter le 02/07/2010 18:57:25

Pour freyr86 ,

Premièrement, prévenir les erreurs en utilisant la constante Windows pour le répertoire système, ce qui donnera toujours un "path" correct.

Détecter l'erreur est une chose, donner à l'utilisateur le choix de réparer est la chose suivante à faire.

If varAppli = 0 Then    
    'si le gestionnaire des taches n'est pas à l'endroit prévu
    varMess = MsgBox("Le gestionnaire des taches n'est pas sur ce chemin d'accès." & vbCRLF & "Désirez-vous sélectionner le chemin d'accès vous-même ?", vbYesNo + vbQuestion, "Erreur d'accès")

if varMess=vbYes then
    ' laisser l'usager choisir et continuer
else
    ' continuer sans....
end if
End If

Commentaire de freyr86 le 02/07/2010 22:55:58

Merci Bitshfter pour cette presision...

 Ajouter un commentaire




Nos sponsors


Sondage...

CalendriCode

Février 2012
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
272829    

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,265 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales