Die Reduzierung doppelte Fehlerbehandlung Code in C #?

stimmen
32

Ich habe nie ganz zufrieden mit der Art und Weise Ausnahme Entladearbeiten gewesen, es eine Menge Ausnahmen ist und try / catch auf den Tisch bringt (Stack Abwickeln, etc.), aber es scheint in dem Prozess viel von dem OO-Modell zu brechen.

Wie auch immer, hier ist das Problem:

Angenommen, Sie haben eine Klasse haben, die oder enthalten IO-Operationen vernetzen Datei wickelt (zB Lese und bei einem bestimmten UNC-Pfad irgendwo zu einem gewissen Datei zu schreiben). Aus verschiedenen Gründen wollen Sie nicht, dass diese Operationen IO zum Scheitern verurteilt, wenn Sie also feststellen, dass sie scheitern Sie sie erneut versuchen und halten Sie erneut versuchen sie, bis sie Erfolg haben oder Sie erreichen einen Timeout. Ich habe bereits eine bequeme RetryTimer Klasse, die ich instanziieren und verwenden den aktuellen Thread zwischen den Wiederholungen zu schlafen und bestimmen, wenn die Timeout-Zeit abgelaufen ist, usw.

Das Problem ist, dass Sie eine Reihe von IO-Operationen in mehreren Methoden dieser Klasse haben, und Sie müssen jede von ihnen in try-catch / Retry-Logik wickeln.

Hier ist ein Beispiel-Code-Snippet:

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();
    }
}

Also, wie Sie vermeiden Sie die meisten dieser Code für jede Datei IO-Betrieb in der gesamten Klasse zu duplizieren? Meine Lösung war anonyme Delegaten Blöcke und eine einzige Methode in der Klasse zu verwenden, die die Delegaten Block an sie übergibt ausgeführt. Das erlaubte mir, Dinge wie diese in anderen Verfahren zu tun:

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

Ich mag dies etwas, aber es lässt viel zu wünschen übrig. Ich möchte hören, wie andere Leute diese Art von Problem lösen würde.

Veröffentlicht am 04/08/2008 um 20:21
quelle vom benutzer
In anderen Sprachen...                            


4 antworten

stimmen
13

Das sieht aus wie eine ausgezeichnete Gelegenheit , einen Blick auf Aspect Oriented Programming zu haben. Hier ist ein guter Artikel auf AOP in .NET . Die allgemeine Idee ist , dass Sie das übergreifende Anliegen (dh Retry für x Stunden) in eine separate Klasse extrahieren würde und dann würde man alle Methoden mit Anmerkungen versehen, die ihr Verhalten in dieser Art und Weise ändern müssen. Hier ist , wie es (mit einer schönen Erweiterungsmethode auf Int32) aussehen könnte

[RetryFor( 10.Hours() )]
public void DeleteArchive()
{
  //.. code to just delete the archive
}
Beantwortet am 05/08/2008 um 10:43
quelle vom benutzer

stimmen
4

Nur frage mich, was fühlen Sie sich Ihre Methode zu wünschen übrig lässt? Sie könnten die anonymen Delegaten mit einem ersetzen .. benannt? delegieren, so etwas wie

    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" );
    }
Beantwortet am 04/08/2008 um 21:07
quelle vom benutzer

stimmen
2

Hier ist, was ich vor kurzem tat. Er wird wahrscheinlich bereits an anderer Stelle besser gemacht, aber es scheint ziemlich sauber und wiederverwendbar.

Ich habe eine Dienstprogramm Methode, die wie folgt aussieht:

    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);
    }

Dann in meiner Anwendung verwende ich c # 's Lamda Ausdruck Syntax Dinge zu halten, ordentlich:

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

Dies erfordert meine Methode und Wiederholungen bis zu 5 mal. Beim fünften Versuch wird die ursprüngliche Ausnahme innerhalb einer Wiederholungs Ausnahme erneut ausgelöst.

Beantwortet am 13/09/2010 um 03:25
quelle vom benutzer

stimmen
2

Sie könnten auch einen mehr OO Ansatz verwenden:

  • Erstellen Sie eine Basisklasse, die die Fehlerbehandlung tut und ruft eine abstrakte Methode, um die konkrete Arbeit zu verrichten. (Schablonenmethode)
  • Erstellen Sie konkrete Klassen für jeden Vorgang.

Dies hat den Vorteil, jede Art von Betrieb zu benennen Sie durchführen und gibt Ihnen ein Befehlsmuster - Operationen als Objekte dargestellt wurden.

Beantwortet am 07/08/2008 um 12:30
quelle vom benutzer

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