Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

Δεν δουλεύει το RETURN στην Fınally του try ... catch

Îåêßíçóå áðü ôï ìÝëïò Ηλίας Κεκάκος. Τελευταία δημοσίευση από το μέλος cap στις 03-03-2009, 07:49. Υπάρχουν 3 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  02-03-2009, 11:00 48806

    Δεν δουλεύει το RETURN στην Fınally του try ... catch

    Γειά σας και καλή Σαρακοστή,

    Dim Succeed As Boolean = False
    Try
    DatasetUser = GetUser()

    If DatasetUser IsNot Nothing Then
    If DatasetUser.Tables.Count > 0 Then
    Succeed = True
    End If
    End If
    Catch ex As Exception

    Finally
    Return Succeed
    End Try

    Αυτό όμως μου επιστρέφει το εξής error: Branching out of a 'Finally' is not valid.
    Κόλησα, μπορεί να μου πεί κάποιος πως θα επιστρέψω την μεταβλητή είτε περάσει από το catch είτε όχι.

    Ευχαριστώ



  •  02-03-2009, 11:34 48807 σε απάντηση της 48806

    Απ: Δεν δουλεύει το RETURN στην Fınally του try ... catch

    Από ο,τι φαίνεται στο catch δεν θέλεις να κάνεις rethrow το exception (οπου σε αυτή την περίπτωση δεν θα είχε νόημα ούτως η άλλως το return) αλλά θέλεις να δώσεις μια τιμή στη μεταβλητή succeed. Μπορείς λοιπόν να δώσεις Succeed = false εντός του catch block και φυσικά η εκτέλεση του προγράμματος θα συνεχιστεί, εφόσον δεν κάνεις rethrow το exception.

    Επειτα, μπορείς μετά το end try να κάνεις return Succeed με ό,τι τιμή έχει πάρει. Ετσι θα έχεις είτε true (δεν μπήκε στο catch block) είτε false (επειδή μπήκε στο catch block).


    Σωτήρης Φιλιππίδης

    DotSee Web Services

    View Sotiris Filippidis's profile on LinkedIn

    DotNetNuke them!
  •  02-03-2009, 23:56 48818 σε απάντηση της 48806

    Απ: Δεν δουλεύει το RETURN στην Fınally του try ... catch

    Πράγματι, δεν επιτρέπεται να βγεις από ένα Finally με Return ή GoTo. Αν το σκεφτείς, το finally υπάρχει μόνο και μόνο για να καθαρίσεις τυχόν αλλαγές που έχεις κάνει ακόμα και αν έχει εμφανιστεί exception. Αν σου επιτρεπόταν να βγεις με return ή GoTo, ακόμα και σε περίπτωση που έχει ήδη εμφανιστεί exception, θα μπορούσες να γράψεις εξαιρετικά επικίνδυνο κώδικα. Όπως σου λέει και ο Σωτήρης, μπορείς πολύ απλά να εκτελέσεις τη Return μετά το End Try και να ξεφορτωθείς την Finally.

    Ακόμα και έτσι όμως, αυτό που προσπαθείς να κάνεις είναι εξαιρετικά επικίνδυνο. Είναι πολύ κακή ιδέα να κουκουλώνεις ένα exception και να επιστρέφεις true/false. Πολύ απλά, αυτός που καλεί το function σου μπορεί να ξεχάσει να ελέγξει το αποτέλεσμα και να συνεχίσει να δουλεύει χρησιμοποιώντας π.χ. λανθασμένα δεδομένα, ή να προσπαθήσει να χρησιμοποιήσει κάποιο πίνακα ο οποίος είναι άδειος.

    Είναι σαν να "διορθώνεις" μία καμένη ασφάλεια τυλίγοντας την με ... αλουμινόχαρτο. Έχω δει χρηματιστηριακή εφαρμογή που χρησιμοποιούσε τέτοια κολπάκια. Κάποια στιγμή, άρχισαν να εμφανίζονται μηδενικά υπόλοιπα σε κάποιους λογαριασμούς. Ψάχνοντας, βρήκα ότι η συνάρτηση που επέστρεφε τις ισοτιμίες νομισμάτων σε κάποιες ημερομηνίες επέστρεφε 0. Βλέπεις, όποιος έφτιαξε τη συνάρτηση ξέχασε να ελέγξει τί του επέστρεφε η αντίστοιχη συνάρτηση του data layer η οποία ... επέστρεφε false σε περίπτωση λάθους.

    Ο σωστός τρόπος να χειρίζεσαι σφάλματα και exceptions είναι να τα χειρίζεσαι αν μπορείς, αλλιώς να τα αφήσεις να προχωρήσουν στις παραπάνω συναρτήσεις, μέχρι να βρεθεί κάποια συνάρτηση που θα μπορέσει να τα χειριστεί. Φαντάσου, για παράδειγμα, ότι έχεις τις παρακάτω συναρτήσεις:

    void TransferMoney(Account a, Account b,decimal amount)
    {
    Widthraw(a,amount);
    Deposit(b,amount);
    }

    void Withdraw(Account a, decimal amount)
    {

    }

    void Deposit(Account a, decimal amount)
    {
    }

    Για λόγους ευκολίας, ας υποθέσουμε ότι μόνο η Deposit μπορεί να εμφανίσει exception. Φαντάσου ότι κάποιο exception εμφανίζεται μέσα στην Deposit. Μπορεί η Deposit να αντιμετωπίσει την κατάσταση? Μάλλον όχι. Μπορεί μεν να ακυρώσει την κατάθεση των χρημάτων στο λογαριασμό Β αλλά δεν μπορεί να ακυρώσει την ανάληψη από το λογαριασμό Α. Συνεπώς, θα πρέπει το exception να πιαστεί μέσα στην TransferMoney για να ακυρωθεί η ανάληψη από τον Α. Και επειδή η ακύρωση μίας μεταφοράς χρημάτων είναι σημαντικό πρόβλημα, θα πρέπει να ξαναριχτεί το exception για να ειδοποιηθεί όποιος ξεκίνησε τη συναλλαγή ότι κάτι πήγε στραβά. Θα πρέπει δηλαδή να γραφτεί κάτι σαν αυτό:

    void TransferMoney(Account a, Account b,decimal amount)
    {
    try
    {
    Widthraw(a,amount);
    Deposit(b,amount);
    catch(Exception ex)
    {
    Deposit(a,amount);
    throw;
    }
    }

    void Withdraw(Account a, decimal amount)
    {
    }

    void Deposit(Account a, decimal amount)
    {
    try
    {
    ....
    }
    catch(Exception ex)
    {
    //Cancel Deposit
    throw;
    }
    }


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  03-03-2009, 07:49 48827 σε απάντηση της 48818

    Απ: Δεν δουλεύει το RETURN στην Fınally του try ... catch

    Να συμφωνήσω και εγώ με τα παραπάνω, σημειώνοντας οτι αυτά που λέει ο Παναγιώτης είναι ουσιαστικά η extended version αυτού που είπα (και αυτών που παρέλειψα).



    Σωτήρης Φιλιππίδης

    DotSee Web Services

    View Sotiris Filippidis's profile on LinkedIn

    DotNetNuke them!
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems