2011-11-22 17 views
5

Tak więc ostatnio piszę stosunkowo złożoną aplikację napisaną w języku C#, która wykonuje wiele małych zadań wielokrotnie. Kiedy po raz pierwszy uruchomiłem aplikację, zdałem sobie sprawę, że wiele kodu, który pisałem, było powtarzalne i dlatego zacząłem enkapsulować większość logiki aplikacji w oddzielne klasy pomocnicze, które mogłem wywołać w razie potrzeby.Gdzie jest prawidłowe miejsce do obsługi wyjątków w aplikacjach C#?

Nie trzeba dodawać, że wielkość mojej aplikacji (i ilość kodu) została zmniejszona o połowę. Ale gdy przechodziłem, zauważyłem coś innego w mojej aplikacji, które wydawało się być powtarzalne i wyglądało na to, że można je poprawić.

Teraz większość moich metod w moim klas pomocniczych są albo dokonywania HttpWebRequest lub wykonywania Zapisz/usuń operacji na plikach. Powiedziawszy, że muszę poradzić sobie z możliwością, że połączenie się nie zakończy, lub plik nie może zapisać, ponieważ nie ma wystarczająco dużo miejsca lub cokolwiek innego. Problemem, który napotykam, jest to, że muszę ciągle pisać instrukcje try/catch za każdym razem, gdy wywołuję jedną z metod. Oprócz tego muszę ponownie wpisać komunikat o błędzie (lub W końcu komunikat o stanie. Chciałbym wiedzieć, kiedy to się uda).

Więc oto niby urywek co mam wpisać:

try 
    { 
    ItemManager.SaveTextPost(myPostItem); 
    } 
    // Majority of the time there is more than one catch! 
    catch 
    { 
    //^^^Not to mention that I have to handle multiple types of exceptions 
    //in order to log them correctly(more catches..ugh!) 
    MessageBox.Show("There was an error saving the post."); 
    //Perform logging here as well 
    } 

Z tego co zawarły tak daleko jest:

  • Dla mnie to jest przesada konieczności pisania w tym ponad 50 razy dla mojej aplikacji. Wygląda na to, że powinienem to uwzględnić w klasie pomocnika, a to pełny zestaw połowów.
  • Ale jak mogę znać wynik? Być może myślałem o zwrocie ciąg , który zawiera komunikat o błędzie/powodzenie.
  • Naprawdę w przypadku tych metod nie jest wymagana metoda, z której wywoływana jest metoda pomocnika, aby zamknąć ją w bloku try/catch.

Czy to podejście jest prawidłowe? Czy istnieje inny sposób robienia tego? Czy powinienem używać metody try/catch w metodzie wywołania? Od tego rodzaju moich pierwszych ujęć chciałbym usłyszeć, co mają do powiedzenia inni, którzy mieli do czynienia z tym scenariuszem.

+0

Podobne pytanie zadano niedawno: http://stackoverflow.com/questions/8156530/exception-handling-in-method-definition-or-call/8156574#8156574 – Tudor

Odpowiedz

1

Myślę, że umieszczenie try/catch w metodzie, do której dzwonisz jest całkowicie w porządku. Możesz zwrócić kod błędu/powodzenia do kodu wywołującego na różne sposoby. Wyliczanie uchwytów .NET i C# ładnie, więc możesz mieć ItemManager.SaveTextPost(myPostItem, out errorCode);, gdzie errorCode byłby wyliczoną wartością, która dałaby ci znać, gdyby wystąpiły jakieś problemy. Może to być równie proste, jak gdyby metoda zwróciła wartość logiczną true, jeśli zakończyła się pomyślnie, false, jeśli jest inaczej. Jest wiele sposobów na poradzenie sobie z tym problemem, ale jeśli chodzi o mnie, metoda "próbuj/złap" w tej metodzie jest preferowanym sposobem robienia rzeczy.

+0

+1 za odesłanie wyliczonej wartości. Myślę, że to świetny pomysł. W jakiś sposób wiedziałem, że jest lepszy sposób niż wysyłanie haha ​​ze stringami. – loyalpenguin

+0

Nie pójdę z metodą "SaveTextPost (myPostItem, out errorCode)". Może to być mylące dla osób używających kodu i jest o wiele trudniejsze w utrzymaniu z wyliczeniem wartości błędów. Poza tym, czy wyjątki nie mają na celu naprawienia błędów? Zwraca wartość boolean, ale jeśli 'true' i' false' są wystarczające dla ciebie. – Otiel

+0

Wyjątki dotyczą błędów, ale nie powinieneś polegać na wyrzucaniu jednego za każdy błąd. Wszystko, czego oczekuje się, że może pójść nie tak powinno być obsługiwane z wdziękiem i wszystko inne, co jest wyjątkowym zdarzeniem, powinno rzucić wyjątek (doskonałym przykładem jest obsługa systemu plików IO - nie masz pojęcia, w jakim stanie znajduje się plik i jakie inne procesy mogą obsługiwać otwarte na tym). Wyrzucanie wyjątków jest kosztowne i używanie ich w miejsce defensywnych praktyk programistycznych to po prostu złe kodowanie w mojej opinii. –

1

AOP biblioteki jak PostSharp są przeznaczone do obsługi obawy przekrojowe dokładnie jak ten.

Jeśli wszystkie te metody pomocnicze wykorzystują tę samą tabelę podstawową, próbuj złapać -> obsługują wiele typów wyjątków, możesz napisać jeden aspekt, który to robi, i udekorować wszystkie odpowiednie metody odpowiednim atrybutem.

1

Nie ma jednej idealnej reguły dla obsługi wyjątków, więc odpowiedź brzmi: To zależy. Generalnie powinieneś wychwytywać wyjątki, jeśli wiesz, jak sobie z nimi radzić. W twoim przykładzie moje pierwsze pytanie byłoby, gdyby aplikacja mogła nadal działać po tym błędzie i nadal byłaby w prawidłowym stanie.Jeśli nie, powinieneś ponownie zgłosić wyjątek po zalogowaniu. Następnie pomyśl o wyjątku zagnieżdżania: możesz złapać wyjątek, dodać informacje, zagnieżdżając je w innym i rzucając ten wyjątek. Jeśli starannie zaprojektujesz klasy wyjątków i procedury obsługi, Twój kod logowania i wyświetlania powinien stać się znacznie prostszy, niż można się tego spodziewać. Ale szczegóły zależą oczywiście od twojej aplikacji.

1

należy rzucać wyjątków w swoich metod pomocniczych sprawdzając z if bloków, jeśli każdy argument jest poprawna, każdy plik jest osiągalny ... a następnie w razie potrzeby wdrożyć pewne try catch bloków w twoich metod pomocniczych i rzucać wyjątki podczas połowu.

Wreszcie, należy ująć te metody pomocnika przez try catch bloku, ale w tym czasie, naprawdę catch wyjątki:

try 
{ 
    ItemManager.SaveTextPost(myPostItem); 
    // SaveTextPost can throw some exceptions (that you know) 
} 
catch (Exception e) 
{ 
    // You know the exceptions that SaveTextPost can return, so threat them 
    // correctly 
    if (e is FileNotFoundException) 
     MessageBox.Show("The file was not found when saving the post."); 
    else if (e is ArgumentNullException) 
     MessageBox.Show("The post can't be null to be saved."); 
    else 
     MessageBox.Show("There was an error saving the post."); 
} 

Na koniec, trzeba traktować błąd i pokazać komunikat o błędzie dla użytkownika. Możesz zdecydować, czy kod MessageBox.Show powinien zostać zaimplementowany w metodzie pomocnika, czy w klasie wywołującej metodę pomocnika.
Osobiście uważam, że metody pomocnicze są przeznaczone do użycia przez każdego programistę, który uruchomi Twój kod, więc powinieneś pozwolić mu zdecydować, co chce zrobić z tym błędem. Oznacza to odrzucanie wyjątków w metodzie pomocnika.

+0

Tak, ale będzie to celem zamknięcia metody w bloku try/catch, jeśli metoda, którą wywołuje, obsługuje możliwe wyjątki. Szczerze mówiąc, chciałbym od tego uciec. Przypuszczam, że istnieje 99,9% szans, jak to się może nie udać ... – loyalpenguin

+0

+1 Nie miałem pojęcia, że ​​można określić typ wyjątku w ten sposób. Coś się nauczyło. Zdecydowanie zgadzam się również, że sposób, w jaki twórca zdecyduje się przekazać wiadomość (czasami nigdy), powinien być pozostawiony do nich. – loyalpenguin

+2

Tego typu porównanie nie będzie działać dla tego, co próbuje zrobić .. musi być coś takiego, jak (e jest FileNotFoundException) {} – iamkrillin

0

Moje osobiste podejście do obsługi wyjątków jest .. dodaj try {} catch {} gdzie ma to sens.

Na przykład zawsze używaj catch catch podczas wywoływania "niezaufanego" kodu, tj. Modułów lub wtyczek. w przeciwnym razie, jeśli zamierzasz złapać wyjątek, upewnij się, że możesz zrobić z nim coś znaczącego. Jeśli nie, pozwól wyjątkowi przepalić się do punktu, w którym możesz.

Jest kilka rzeczy gorszych niż próba debugowania aplikacji, w której programista wykrył wyjątek i zwrócił wartość logiczną. Wystarczy powiedzieć:

1

Spróbuj/Złap to dobre rozwiązanie. Jedna z propozycji, chciałabym to wykorzystać, aby powstrzymać napływ błędów: Wyjątek połowu: spróbować { } catch (Exception ex) { ShowExceptionError (Ex); } Następnie po prostu wyrzucę wszystkie wyjątki do pojedynczej metody i pozwolę, aby metoda obsługiwała każdy z nich.

Niby tak:

private void ShowExceptionError(ex) 
{ 
    string errorMessage = "Type of error:" + ex.GetType().ToString(); 
    string stackTrace = ex.StackTrace(); 
    MessageBox.Show(errorMessage + "\n\n" + stackTrace); 
} 
1

Wszystkie te sposoby są wielkie możliwości. Jedną z rzeczy, których nie chcesz robić, jest użycie try {} catch {} do kontroli przepływu. Oznacza to coś takiego (ponownie uniknij tego)

Void SomeMethod() 
{ 
    try 
    { 
     while(somecondition) 
     { 
      try 
      { 
      } 
      catch (Exception ex) 
      { 

      } 
      } 
    } 
    catch (Exception ex) 
    { 
      ..... 
    } 

Zamiast tego chcesz kodować defensywnie.

Powiązane problemy