
Είναι δομημένη Εξαίρεση Χειρισμός κακό; Ποιος είναι ο σωστός τρόπος για να χειριστεί τις εξαιρέσεις;


**EDIT: Εξαίρεση Χειρισμός σε .NET χρησιμοποιώντας C #.**


Έχω συνήθως μια σειρά από ειδικές κατηγορίες εξαίρεση (DivideByZeroException, ArrayTypeMismatchException) και δεν έχουν ένα γενικό «αλιευμάτων (Εξαίρεση πρώην)».


Η σκέψη πίσω από αυτό είναι ότι περιμένω ορισμένους τύπους εξαιρέσεων να συμβεί και να έχουν συγκεκριμένων δράσεων που όταν εμφανίζονται και οι απροσδόκητες εξαιρέσεις θα ανέβει τα η διεπαφή (είτε παράθυρα ή web). Είναι αυτή μια καλή πρακτική;

 
εξαίρεση Χειρισμός
==================



Δεν είμαι σίγουρος τι εννοείτε με «δομημένη χειρισμό εξαίρεση». 


Το χειρότερο πράγμα που μπορεί να γίνει στο χειρισμό εξαίρεση είναι να «καταπιεί» την εξαίρεση ή να χειριστεί το σιωπηλά.


Μην το κάνεις αυτό:



```
try {
   ...
}
catch (Exception e) {
   //TODO: handle this later
}

```

Αυτό είναι πολύ συχνά γίνεται από τεμπελιά για να πάρει κωδικό για την κατάρτιση. Αν δεν ξέρετε πώς να χειριστεί την εξαίρεση σε ένα συγκεκριμένο επίπεδο, πρέπει η μέθοδος να ρίξει την εξαίρεση και έχουν τουλάχιστον ένα Πιάσε όλα χειριστή στην κορυφή. Τα σχόλιά σας με κάποιο τρόπο (μέσω του GUI, μια σελίδα / e-mail σε ένα άτομο υποστήριξης, το αρχείο καταγραφής), έτσι ώστε το θέμα να πάρει τελικά σταθερή. Σιωπηλά πιάσει μια εξαίρεση σχεδόν πάντα οδηγεί σε ένα μεγαλύτερο ζήτημα που συμβαίνει αργότερα και είναι δύσκολο να εντοπιστεί.

 

Δηλώσεις αλιευμάτων + Stack ίχνη. Μην πάρετε ποτέ μια εξαίρεση χωρίς να εκτυπώσετε ένα stack trace, εσείς ή κάποιος άλλος θα πρέπει να την ολοκλήρωση της παραγγελίας αυτόν τον κωδικό ξανά και ίχνη θέση στοίβα στο μπλοκ Catch όταν παρουσιάζεται ένα σφάλμα και τα αρχεία καταγραφής σας είναι είτε άδειο ή ασαφείς.

 

Αυτό είναι ένα πολύπλοκο θέμα ... υπάρχουν βιβλία για αυτό ... αλλά ... Υπάρχουν δύο κύριοι τύποι χειρισμό εξαίρεση ... inline, όπου κωδικό για την αντιμετώπιση πιθανών λαθών είναι ενσωματωμένο με τον κώδικα που μια μέθοδο ή ρουτίνα θα «κανονικά» να εκτελέσει, και δομημένη χειρισμό εξαίρεση, όταν ο κωδικός είναι αλλού, και Teh υποδομή είναι σχεδιασμένη για να switych αυτόματα στον κώδικα χειρισμό εξαίρεση, όταν συμβεί ένα απροσδόκητο γεγονός (σφάλμα) ... και οι δύο έχουν advantedges και disadvanteges. Η προσέγγιση «inline» τείνει να παράγει κώδικα η οποία είναι πολύ πιο γεμάτα (με τον κωδικό σφάλματος) και πιο δύσκολο να διαβάσει και να διατηρηθεί. Αλλά είναι πιο εύκολο να παράγουν μπροστά, καθώς δεν απαιτεί καμία εκ των προτέρων ανάλυση, Όταν χρησιμοποιείτε ενσωματωμένη διαχείριση σφαλμάτων, βλέπετε συχνά μεθόδους που επιστρέφουν boolean ή το αριθμητικό «λάθος» τους κωδικούς, indiocating στον καλούντα αν η metjhod ή ρουτίνα ήταν επιτυχής. Αυτό εξαλείφει την «λειτουργική» σύνταξη με μια ρουτίνα «επιστροφή» μια σημαντική επιχειρηματική αξία ή αντικείμενο, (από κάθε λειτουργία, κατά συνθήκη, πρέπει να επιστρέφει έναν κωδικό σφάλματος) Όταν χρησιμοποιείτε δομημένη χειρισμό εξαίρεση, το θέμα αυτό είναι αμφισβητήσιμο.


Δομημένη χειρισμό εξαίρεση, OTOH, σε γενικές γραμμές είναι πιο δύσκολο να κάνει καλά, καθώς απαιτεί εκ των προτέρων ανάλυση για το τι λάθη ρουτίνα ή η μέθοδος θα μπορούσε ενδεχομένως να παράγουν, και ως προς το ποια είναι η μέθοδος μπορεί ή πρέπει να κάνουμε για κάθε λάθος αν συμβεί. 


Ένα πράγμα είναι σίγουρο, Μην αναμιγνύετε τα δύο προσεγγίσεων σε ένα και μόνο συστατικό ... 

 

Η σύστασή μου:


Μην πάρετε μια εξαίρεση, εκτός εάν:


* Σε αντίθετη περίπτωση, θα μπορούσε να προκαλέσει η εφαρμογή για την συντριβή (π.χ. σε ένα πρόγραμμα χειρισμού συμβάντων)
	+ Και σε αυτή την κατάσταση, να είστε βέβαιος να καταγράψει την εξαίρεση, ώστε να ξέρετε τι συνέβη και πότε
* Μπορείτε να κάνετε κάτι για να προσπαθήσουμε και να διορθώσει την κατάσταση (π.χ. εφαρμογή ενός μηχανισμού επανάληψης όταν καλείτε ένα εξωτερικό API που ρίχνει περιστασιακά μια εξαίρεση (σημειώστε ότι το χειρισμό εξαίρεση, δεν θα πρέπει να χρησιμοποιείται για τον έλεγχο της ροής του προγράμματος))
	+ Και σε αυτή την κατάσταση, να πιάσει μόνο τον συγκεκριμένο τύπο εξαίρεσης που περιμένετε να πάρετε ρίχνονται


Η σύλληψη της εξαίρεσης στο υψηλότερο δυνατό επίπεδο σημαίνει ότι θα έχετε τη μέγιστη στοίβα κλήσεων, το οποίο είναι πολύ χρήσιμο όταν περνάτε από τα κούτσουρα και προσπαθούμε να δούμε τι η αρχική ενέργεια προκάλεσε την ακολουθία των γεγονότων που οδήγησαν στην εξαίρεση στην πρώτη θέση .

 

Δεν είμαι προγραμματιστής των Windows, αλλά μου φαίνεται ότι με τη χρήση δομημένου χειρισμού εξαιρέσεων για την αντιμετώπιση εξαιρέσεις υλικού, όπως εξαιρέσεις λογισμικό σημαίνει ότι:


* Ο κωδικός σας κάνει κάτι που στην C ++ τυπική παράγει ορισμένες ή εφαρμογής που ορίζονται από τη συμπεριφορά (όπως η διαίρεση με το μηδέν).
* Παράθυρα ορίζει ότι με ενεργοποιημένο SEH ρίχνει μια εξαίρεση σε αυτή την περίπτωση.
* Χρησιμοποιείτε αυτό το γεγονός για να πιάσει την εξαίρεση και / ή να εκτελέσει ένα πρόγραμμα χειρισμού τερματισμού.


Έτσι, οι ερωτήσεις να ρωτήσω, ΙΜΟ, είναι οι εξής:


* Είναι έργο του προγραμματισμού σας είναι πραγματικά ένα χαρακτήρα που πρότυπο C ++ δεν μπορεί να χειριστεί; (Ή μπορεί να χειριστεί μόνο με έναν τρόπο που είναι μετρήσιμα κατώτερα από ό, τι μπορείτε να πάρετε, επιτρέποντας την εξαίρεση του υλικού).
* Πιστεύετε πραγματικά πρέπει να αναλάβει δράση όταν κωδικό σας πηγαίνει μη τυποποιημένων;
* Μπορείτε να γράψετε τον κωδικό σας, έτσι ώστε να μην προκαλέσει εξαιρέσεις υλικό στην πρώτη θέση;


Αν οι απαντήσεις είναι «ναι», «ναι», «όχι», είναι απαραίτητη στη συνέχεια, δομημένη χειρισμό εξαίρεση. Διαφορετικά, ενδέχεται να μπορείτε να το αποφύγετε, οπότε μάλλον θα θέλετε να. Γράφοντας εξαίρεση ασφαλές κώδικας είναι δύσκολο, τόσο ισχυρότερη είναι η εξαίρεση εγγυήσεις που μπορεί να προσφέρει το καλύτερο. Κωδικός που χωρίζει ίσως από το μηδέν με SEH δεν προσφέρει την εγγύηση nothrow, όταν ίσως με λίγο επανασχεδιασμό, έτσι ώστε οι καλούντες να μην δώσει στοιχεία Duff, θα μπορούσε να το κάνει. Αλλά αν μια συνάρτηση έχει ήδη ρίξει εξαιρέσεις για άλλους λόγους, τότε και, ενδεχομένως, ρίχνοντας τους για τις παγίδες του υλικού μπορεί να κάνει τα πράγματα δεν είναι χειρότερα.


Μια αξιοσημείωτη ειδική περίπτωση είναι εκχώρησης μνήμης. Δεν είμαι σίγουρος αν .NET κάνει αυτό, αλλά για την κατανομή του linux δεν μόνο εάν υπάρχει επαρκής χώρος εικονικών διευθύνσεων για την κατανομή. Φυσικής μνήμης δεσμεύεται για την πρώτη χρήση, και προκαλεί μια εξαίρεση υλικού, εάν δεν υπάρχει αρκετή. Από την κατανομή μνήμης *πρέπει* να ρίξει std :: bad\_alloc σε αποτυχία, και η εφαρμογή δεν εφαρμόζει αυτή την απαίτηση του προτύπου, που *μπορεί* να είναι ότι, σε ορισμένες περιπτώσεις, μετατρέποντας την εξαίρεση του υλικού στο λογισμικό είναι το σωστό πράγμα που κάνει. Ωστόσο, η εξαίρεση του υλικού μπορεί να συμβεί σε απροσδόκητες θέσεις, (συμπεριλαμβανομένων ρουτίνες νόμιζες ότι ήταν nothrow), οπότε μπορεί να εξακολουθεί να είναι αδύνατο να χειριστεί με χάρη, αυτός είναι ο λόγος πυρήνα linux χωματερές αντί να ρίχνουν. Στην πράξη, κάτι που γίνεται σε εκκίνηση θα διακοπεί η λειτουργία του κατασκευαστή του, η οποία είναι συχνά αρκετά κοντά με την κατανομή που η εξαίρεση του λογισμικού αντί θα ήταν χρήσιμο πλήρως.

 