Zmniejszenie duplikat kod obsługi błędów w C #?

głosy
32

Nigdy nie byłem w pełni zadowolony ze sposobu ładowania, wyjątek, istnieje wiele wyjątków i spróbuj / połów przynosi do stołu (stack odwijania, etc.), ale wydaje się, aby przełamać wiele modelu OO w tym procesie.

W każdym razie, tu jest problem:

Powiedzmy, że masz jakąś klasę, która otacza lub obejmuje operacje IO plików w sieci (np czytanie i pisanie do jakiegoś pliku w jakiejś konkretnej ścieżki UNC gdzieś). Z różnych powodów nie chcesz te operacje IO na niepowodzenie, więc jeśli wykryje, że nie je ponownie i zachować Ponowna próba ich dopóki nie uda lub osiągnięciu limitu czasu. Mam już dogodnym klasę RetryTimer które mogę instancję i korzystania spać bieżącego wątku między próbami i określić, kiedy upłynie limit czasu, itd.

Problemem jest to, że masz kilka operacji IO w kilku metod tej klasy, i trzeba owinąć każdy z nich w try-catch logiki / ponawiania.

Oto urywek przykład kodu:

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

Tak więc, w jaki sposób uniknąć powielania większość tego kodu dla każdego pliku operacji IO całej klasy? Moje rozwiązanie było użyć anonimowych bloków delegowanego i jedną metodę w klasie, który wykonywany blok delegata przekazany do niego. To pozwoliło mi robić rzeczy, jak to w innych metod:

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

Lubię to nieco, ale pozostawia wiele do życzenia. Chciałbym usłyszeć, jak inni ludzie by rozwiązać tego typu problemu.

Utwórz 04/08/2008 o 20:21
źródło użytkownik
W innych językach...                            


4 odpowiedzi

głosy
4

Po prostu zastanawiasz się, co czujesz metoda pozostawia do życzenia? Można wymienić anonimowy delegata z .. nazwie? delegat, coś jak

    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" );
    }
Odpowiedział 04/08/2008 o 21:07
źródło użytkownik

głosy
13

To wygląda na doskonałą okazję, aby rzucić okiem na Aspect Oriented Programming. Oto dobry artykuł na AOP w .NET . Ogólna idea jest taka, że chcesz wyodrębnić troskę cross-funkcjonalnej (czyli ponownych prób dla x godzin) do osobnej klasy, a potem, że opisywanie żadnych metod, które muszą modyfikować swoje zachowanie w ten sposób. Oto jak może wyglądać (z ładnym metodę rozszerzenia na Int32)

[RetryFor( 10.Hours() )]
public void DeleteArchive()
{
  //.. code to just delete the archive
}
Odpowiedział 05/08/2008 o 10:43
źródło użytkownik

głosy
2

Można też użyć bardziej podejście OO

  • Tworzenie klasy bazowej, która wykonuje obsługę błędów i wywołuje abstrakcyjną metodę, aby wykonać konkretną pracę. (Metoda szablonowa)
  • Stworzą konkretne zajęcia dla każdej operacji.

Ma to tę zaletę nazywania każdego typu operacji wykonać i daje wzór Command - operacje zostały przedstawione jako obiekty.

Odpowiedział 07/08/2008 o 12:30
źródło użytkownik

głosy
2

Oto co zrobiłem w ostatnim czasie. To prawdopodobnie zostały zrobione gdzie indziej lepiej, ale wydaje się dość czyste i wielokrotnego użytku.

Mam metodę narzędziowy, który wygląda tak:

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

Wtedy w mojej aplikacji, używam składni wyrażeń C # 's Lamda utrzymać porządek rzeczy:

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

Wymaga to moją metodę i ponawia do 5 razy. Na piątym próbie oryginalny wyjątek rethrown wewnątrz wyjątkiem ponownej próby.

Odpowiedział 13/09/2010 o 03:25
źródło użytkownik

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