Μείωση διπλούν κώδικα χειρισμού σφαλμάτων σε C #;

ψήφοι
32

Δεν έχω πάει ποτέ απόλυτα ικανοποιημένος με τον τρόπο που λειτουργεί το χειρισμό εξαίρεση, υπάρχει πολύ εξαιρέσεις και να προσπαθήσουμε / catch φέρνει στο τραπέζι (στοίβα χαλάρωση, κ.λπ.), αλλά φαίνεται να σπάσει ένα μεγάλο μέρος της μοντέλο OO στη διαδικασία.

Τέλος πάντων, εδώ είναι το πρόβλημα:

Ας πούμε ότι έχετε κάποια τάξη, η οποία αναδιπλώνεται ή περιλαμβάνει λειτουργίες IO δικτυωμένων αρχείων (π.χ. ανάγνωση και γραφή σε κάποιο αρχείο σε κάποιο συγκεκριμένο διαδρομή UNC κάπου). Για διάφορους λόγους που δεν θέλετε οι πράξεις αυτές IO να αποτύχει, οπότε αν έχετε εντοπίσει ότι δεν μπορείτε να επαναλάβετε και να σας κρατήσει προσπαθήσετε ξανά τους μέχρι να πετύχουν ή να φτάσετε σε ένα χρονικό όριο. Έχω ήδη ένα βολικό κατηγορίας RetryTimer οποία μπορώ να υπόσταση και να χρησιμοποιήσει για να κοιμηθεί το τρέχον νήμα μεταξύ επαναλήψεων και να καθορίσει πότε έχει περάσει το διάστημα αναμονής, κ.λπ.

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

Εδώ είναι ένα απόσπασμα παράδειγμα κώδικα:

RetryTimer fileIORetryTimer = new RetryTimer(TimeSpan.FromHours(10));
bool success = false;
while (!success)
{
    try
    {
        // do some file IO which may succeed or fail
        success = true;
    }
    catch (IOException e)
    {
        if (fileIORetryTimer.HasExceededRetryTimeout)
        {
            throw e;
        }
        fileIORetryTimer.SleepUntilNextRetry();
    }
}

Έτσι, πώς θα αποφευχθεί η επανάληψη μεγαλύτερο μέρος αυτού του κώδικα για κάθε λειτουργία IO αρχείο σε όλη την τάξη; λύση μου ήταν να χρησιμοποιήσει ανώνυμα μπλοκ εκπρόσωπο και μια ενιαία μέθοδο στην κλάση που εκτελείται το μπλοκ εκπρόσωπο περάσει σε αυτό. Αυτό μου επέτρεψε να κάνουμε τα πράγματα όπως αυτό και σε άλλες μεθόδους:

this.RetryFileIO( delegate()
    {
        // some code block
    } );

Μου αρέσει αυτή η κάπως, αλλά αφήνει πολλά να είναι επιθυμητή. Θα ήθελα να ακούσω πώς άλλοι άνθρωποι θα λύσει αυτό το είδος του προβλήματος.

Δημοσιεύθηκε 04/08/2008 στις 20:21
πηγή χρήστη
Σε άλλες γλώσσες...                            


4 απαντήσεις

ψήφοι
13

Αυτό μοιάζει με μια εξαιρετική ευκαιρία να ρίξετε μια ματιά στο Aspect Oriented Programming. Εδώ είναι ένα καλό άρθρο για AOP στη ΝΕΤ . Η γενική ιδέα είναι ότι θέλετε να εξαγάγετε το σταυρό-λειτουργική ανησυχία (π.χ. Επανάληψη για x ώρες) σε μια ξεχωριστή κατηγορία και, στη συνέχεια, θα ήθελα να σχολιάσετε τυχόν μεθόδους που πρέπει να τροποποιήσουν τη συμπεριφορά τους με αυτόν τον τρόπο. Εδώ είναι πώς αυτό μπορεί να μοιάζει (με ένα ωραίο μέθοδο επέκτασης για Int32)

[RetryFor( 10.Hours() )]
public void DeleteArchive()
{
  //.. code to just delete the archive
}
Απαντήθηκε 05/08/2008 στις 10:43
πηγή χρήστη

ψήφοι
4

Απλά αναρωτιέμαι, τι αισθάνεσαι μέθοδο σας αφήνει να είναι επιθυμητή; Θα μπορούσε να αντικαταστήσει τον ανώνυμο πληρεξούσιο με ένα .. που ονομάζεται; εκπρόσωπο, κάτι σαν

    public delegate void IoOperation(params string[] parameters);

    public void FileDeleteOperation(params string[] fileName)
    {
        File.Delete(fileName[0]);
    }

    public void FileCopyOperation(params string[] fileNames)
    {
        File.Copy(fileNames[0], fileNames[1]);
    }

    public void RetryFileIO(IoOperation operation, params string[] parameters)
    {
        RetryTimer fileIORetryTimer = new RetryTimer(TimeSpan.FromHours(10));
        bool success = false;
        while (!success)
        {
            try
            {
                operation(parameters);
                success = true;
            }
            catch (IOException e)
            {
                if (fileIORetryTimer.HasExceededRetryTimeout)
                {
                    throw;
                }
                fileIORetryTimer.SleepUntilNextRetry();
            }
        }
    }

    public void Foo()
    {
        this.RetryFileIO(FileDeleteOperation, "L:\file.to.delete" );
        this.RetryFileIO(FileCopyOperation, "L:\file.to.copy.source", "L:\file.to.copy.destination" );
    }
Απαντήθηκε 04/08/2008 στις 21:07
πηγή χρήστη

ψήφοι
2

Εδώ είναι αυτό που έκανα πρόσφατα. Πιθανόν να έχει γίνει αλλού καλύτερα, αλλά φαίνεται πολύ καθαρά και επαναχρησιμοποιήσιμα.

Έχω μια μέθοδο εργαλείο που μοιάζει με αυτό:

    public delegate void WorkMethod();

    static public void DoAndRetry(WorkMethod wm, int maxRetries)
    {
        int curRetries = 0;
        do
        {
            try
            {
                wm.Invoke();
                return;
            }
            catch (Exception e)
            {
                curRetries++;
                if (curRetries > maxRetries)
                {
                    throw new Exception("Maximum retries reached", e);
                }
            }
        } while (true);
    }

Στη συνέχεια, στην αίτησή μου, μπορώ να χρησιμοποιήσω Lamda σύνταξη έκφραση 's γ # για να κρατήσει τα πράγματα τακτοποιημένα:

Utility.DoAndRetry( () => ie.GoTo(url), 5);

Αυτό απαιτεί η μέθοδος μου και επαναλήψεις έως και 5 φορές. Κατά την πέμπτη προσπάθεια, η αρχική εξαίρεση rethrown εσωτερικό ενός εξαίρεση επανάληψης.

Απαντήθηκε 13/09/2010 στις 03:25
πηγή χρήστη

ψήφοι
2

Μπορείτε επίσης να χρησιμοποιήσετε μια πιο προσέγγιση OO:

  • Δημιουργήστε μια βασική κλάση που κάνει την αντιμετώπιση των λαθών και ζητεί μια αφηρημένη μέθοδο για να εκτελέσει το συγκεκριμένο έργο. (Μοτίβο Μέθοδος Template)
  • Δημιουργήστε συγκεκριμένες κατηγορίες για κάθε πράξη.

Αυτό έχει το πλεονέκτημα της ονομασίας κάθε τύπο λειτουργίας που εκτελείτε και σας δίνει ένα σχέδιο εντολής - οι εργασίες έχουν παρασταθεί ως αντικείμενα.

Απαντήθηκε 07/08/2008 στις 12:30
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more