Po co łapać i ponownie zgłaszać wyjątki w C #?


557

Patrzę na artykuł C # - Obiekt transferu danych na temat szeregowych DTO.

Artykuł zawiera ten fragment kodu:

public static string SerializeDTO(DTO dto) {
    try {
        XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
        StringWriter sWriter = new StringWriter();
        xmlSer.Serialize(sWriter, dto);
        return sWriter.ToString();
    }
    catch(Exception ex) {
        throw ex;
    }
}

Reszta artykułu wygląda rozsądnie i rozsądnie (dla nooba), ale ten rzut próbny rzuca wyjątek WtfEx ... Czy to nie jest dokładnie równoznaczne z brakiem obsługi wyjątków?

Ergo:

public static string SerializeDTO(DTO dto) {
    XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
    StringWriter sWriter = new StringWriter();
    xmlSer.Serialize(sWriter, dto);
    return sWriter.ToString();
}

A może brakuje mi czegoś fundamentalnego w obsłudze błędów w C #? Jest prawie taki sam jak Java (bez zaznaczonych wyjątków), prawda? ... To znaczy, obaj dopracowali C ++.

Pytanie przepełnienia stosu Różnica między ponownym wyrzucaniem łapania bez parametrów a brakiem działania? wydaje się potwierdzać moją tezę, że try-catch-throw to brak możliwości.


EDYTOWAĆ:

Podsumowując, dla każdego, kto znajdzie ten wątek w przyszłości ...

NIE RÓB

try {
    // Do stuff that might throw an exception
}
catch (Exception e) {
    throw e; // This destroys the strack trace information!
}

Informacje dotyczące śledzenia stosu mogą być kluczowe dla zidentyfikowania pierwotnej przyczyny problemu!

ZROBIĆ

try {
    // Do stuff that might throw an exception
}
catch (SqlException e) {
    // Log it
    if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
        // Do special cleanup, like maybe closing the "dirty" database connection.
        throw; // This preserves the stack trace
    }
}
catch (IOException e) {
    // Log it
    throw;
}
catch (Exception e) {
    // Log it
    throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
    // Normal clean goes here (like closing open files).
}

Złap bardziej szczegółowe wyjątki przed mniej szczegółowymi (tak jak Java).


Bibliografia:


8
Dobre podsumowanie; dodatkowe punkty za dołączenie w końcu bloku.
Fredrik Mörk

chciałbym dodać, że można użyć „rzut”; być jeszcze bardziej pomocnym, dodając parametry, które zostały wysłane do metody w kolekcji e.Data przed „rzutem”; oświadczenie
Michael Bahig

@MickTheWarMachineDesigner (i malarz pracujący w niepełnym wymiarze godzin). Co? Mówisz o obchodzeniu wyjątków od Microshite Suckwell (prawdopodobnie od 2005 r., O ile wiem). Mówiłem ogólnie o obsłudze wyjątków. I tak, nauczyłem się trochę, odkąd opublikowałem WIĘCEJ CZTERY LATA AGO… Ale tak, przyznaję, że masz rację, ale myślę, że przegapiłeś prawdziwy punkt; jeśli dostaniesz mój dryf? To pytanie dotyczy obsługi wyjątków GENERALIZED w języku C #; a dokładniej o przepisywaniu wyjątków ... WSZYSTKICH rodzajów. Fajne?
corlettk

Rozważ przeniesienie sekcji podsumowania edycji w swoim pytaniu do własnej odpowiedzi. Aby dowiedzieć się, dlaczego, zobacz Edytowanie odpowiedzi własnej bez pytania i Odpowiedź osadzona w pytaniu .
DavidRR

2
Czy ktoś nie zauważył części „Wystąpiły odchody”? wygląda na to, że kod poszedł na kupę!
Jason Loki Smith

Odpowiedzi:


430

Pierwszy; sposób, w jaki kod w artykule to robi, jest zły.throw exzresetuje stos wywołań w wyjątku do punktu, w którym znajduje się ta instrukcja throw; utrata informacji o tym, gdzie faktycznie utworzono wyjątek.

Po drugie, jeśli po prostu złapiesz i przerzucisz w ten sposób, nie widzę żadnej wartości dodanej, powyższy przykład kodu byłby tak samo dobry (lub, biorąc pod uwagę throw exbit, nawet lepszy) bez try-catch.

Są jednak przypadki, w których możesz chcieć złapać i ponownie zgłosić wyjątek. Logowanie może być jednym z nich:

try 
{
    // code that may throw exceptions    
}
catch(Exception ex) 
{
    // add error logging here
    throw;
}

6
@Fredrick, po prostu fyi (choć pewnie wiesz), jeśli nie zamierzasz użyć tego exobiektu, nie ma potrzeby tworzenia go.
Eoin Campbell

78
@Eoin: Jeśli nie zostanie utworzony, trudno byłoby go zalogować.
Sam Axe

30
Tak, myślę, że „zło” ma rację… rozważ przypadek wyjątku wskaźnika zerowego wyrzuconego gdzieś z dużej części kodu. Wiadomość jest waniliowa, bez śladu stosu, który został z „coś gdzieś było zerowe”. NIE jest dobre, gdy produkcja jest martwa; i nie masz ani minuty ani minuty, aby rozwiązać problem z flaminem, i odrzucić go lub naprawić ... Dobra obsługa wyjątków jest warta złota.
corlettk

4
Czy dotyczy to również Javy ... „throw” vs. „throw ex”?
JasonStoltz

8
@Jason, zobacz to pytanie . W Javie throw exnie uruchamia ponownie śledzenia stosu.
Matthew Flaschen

117

Nie rób tego

try 
{
...
}
catch(Exception ex)
{
   throw ex;
}

Utracisz informacje śledzenia stosu ...

Albo

try { ... }
catch { throw; }

LUB

try { ... }
catch (Exception ex)
{
    throw new Exception("My Custom Error Message", ex);
}

Jednym z powodów, dla których możesz chcieć ponownie rzucić, jest to, że zajmujesz się różnymi wyjątkami, na przykład

try
{
   ...
}
catch(SQLException sex)
{
   //Do Custom Logging 
   //Don't throw exception - swallow it here
}
catch(OtherException oex)
{
   //Do something else
   throw new WrappedException("Other Exception occured");
}
catch
{
   System.Diagnostics.Debug.WriteLine("Eeep! an error, not to worry, will be handled higher up the call stack");
   throw; //Chuck everything else back up the stack
}

7
Dlaczego nie po prostu całkowicie odrzucić catch?
AnthonyWJones

3
pozostawianie wartości catch {rzut; } na dole listy konkretnych typów wyjątków catch z tego powodu, że dowodzi to, że autor rozpatrzył sprawę, chociaż komentarz może być równie wystarczający. Nie zgadywanie podczas czytania kodu jest dobrą rzeczą.
annakata

87
Z jakiegoś powodu niepokoi mnie nazwa SQLException.
Michael Myers

13
Ten haczyk (wyjątek) {wyrzuć nowy wyjątek (...)} jest czymś, czego nigdy, nigdy, nigdy nie powinieneś robić, po prostu dlatego, że zaciemniasz informacje o wyjątkach i niepotrzebnie utrudniasz filtrowanie wyjątków w górę stosu wywołań. Jedyny raz powinieneś złapać jeden typ wyjątku i rzucić inny, gdy implementujesz warstwę abstrakcji i musisz przekształcić typ wyjątku specyficzny dla dostawcy (np. SqlException versus XmlException) w bardziej ogólny (np. DataLoadingException).
jammycakes 18.10.10

3
@dark_perfect powinieneś sprawdzić ten argument z góry, na początku metody i wrzucić tam ArgumentNullException (szybki błąd).
Andrei Bozantan

56

C # (przed C # 6) nie obsługuje „odfiltrowanych wyjątków” CIL, co robi VB, więc w C # 1-5 jednym z powodów ponownego zgłoszenia wyjątku jest to, że nie masz wystarczającej ilości informacji w momencie catch () aby ustalić, czy rzeczywiście chcesz złapać wyjątek.

Na przykład w VB możesz to zrobić

Try
 ..
Catch Ex As MyException When Ex.ErrorCode = 123
 .. 
End Try

... który nie obsługiwałby MyExceptions z różnymi wartościami ErrorCode. W wersji C # przed wersją 6 trzeba złapać i ponownie wyrzucić MyException, jeśli kod błędu nie wynosił 123:

try 
{
   ...
}
catch(MyException ex)
{
    if (ex.ErrorCode != 123) throw;
    ...
}

Od wersji C # 6.0 możesz filtrować tak samo jak w VB:

try 
{
  // Do stuff
} 
catch (Exception e) when (e.ErrorCode == 123456) // filter
{
  // Handle, other exceptions will be left alone and bubble up
}

2
Dave, ale (przynajmniej w java) nie rzuciłbyś „ogólnego” MyException, zdefiniowałbyś SPECYFICZNY typ wyjątku i rzuciłbyś go, pozwalając na rozróżnienie według typu w bloku catch ... Ale tak , jeśli nie jesteś architektem wyjątku (myślę o SQLException JDBC (znowu Java) tutaj, co jest obrzydliwie ogólne i ujawnia metodę getErrorCode () ... Hmmm ... Masz rację, po prostu Myślę, że jest lepszy sposób, jeśli to możliwe. Pozdrawiam, Mateusz. Bardzo doceniam twój czas. Keith.
Corlettk,

1
Cóż, pytanie brzmi „Po co łapać i ponownie zgłaszać wyjątki w C #?”, I to jest odpowiedź. =] ... a nawet ze specjalnymi wyjątkami, Filtry Wyjątków mają sens: rozważ przypadek, w którym, powiedzmy, obsługujesz SqlTimeoutException i SqlConnectionResetException, które są zarówno SqlException. Filtry wyjątków pozwalają złapać SqlException tylko wtedy, gdy jest to jeden z tych dwóch, więc zamiast zaśmiecać swoją try / catch z identyczną obsługą dla tych dwóch, można „złapać SqlException ex, gdy ex jest SqlTimeoutException Lub ex jest SqlConnectionResetException”. (Nie jestem Dave btw)
bzlm

3
Filtrowane wyjątki będą dostępne w C # 6!
Sir Crispalot,

14

Mój główny powód posiadania kodu, takiego jak:

try
{
    //Some code
}
catch (Exception e)
{
    throw;
}

jest tak, że mogę mieć punkt przerwania w catch, który ma instancję wyjątku. Często to robię podczas programowania / debugowania. Oczywiście kompilator ostrzega mnie przed wszystkimi nieużywanymi literami e, i najlepiej, jeśli powinny zostać usunięte przed kompilacją wydania.

Są jednak miłe podczas debugowania.


1
Tak, zapłacę za to, ale tak, nie chciałbyś tego widzieć w opublikowanym kodzie ... ergo: Wstydziłbym się go opublikować ;-)
corlettk,

25
W rzeczywistości nie jest to konieczne - w Visual Studio możesz ustawić debugger, aby się zepsuł, gdy zostanie zgłoszony wyjątek, i wyświetli on szczegóły wyjątku w oknie inspektora.
jammycakes

8
Jeśli chcesz użyć kodu TYLKO podczas debugowania, użyj #if DEBUG ... #endif i nie musisz usuwać tych linii
Michael Freidgeim,

1
Tak, zrobiłem to kilka razy sam. Co jakiś czas można uciec do wydania. @jammycakes Problem z przerwaniem programu Visual Studio na wyjątek polega na tym, że czasem wyjątek, którego chcę, nie jest jedynym (lub nawet jedynym tego typu) zgłaszanym. Nadal nie znam warunku punktu przerwania z „break, jeśli pominięto go przez wyjątek”. Do tego czasu będzie to przydatne. Michael Freidgeim: #if DEBUGwokół ZARÓWNO try {i } catch () {...}jest trochę niechlujny i, szczerze mówiąc, sprawia, że ​​mam mdłości ... Preprocesor , ogólnie rzecz biorąc, nie jest moim przyjacielem.

11

Prawidłowym powodem ponownego zgłaszania wyjątków może być to, że chcesz dodać informacje do wyjątku lub zawrzeć oryginalny wyjątek w jednym z twoich własnych działań:

public static string SerializeDTO(DTO dto) {
  try {
      XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
      StringWriter sWriter = new StringWriter();
      xmlSer.Serialize(sWriter, dto);
      return sWriter.ToString();
  }
  catch(Exception ex) {
    string message = 
      String.Format("Something went wrong serializing DTO {0}", DTO);
    throw new MyLibraryException(message, ex);
  }
}

Dzięki, owijanie wyjątków tak (szczególnie łańcuchowe) jest całkowicie rozsądne ... to, co nie jest rozsądne, łapie wyjątek tylko po to, abyś mógł odrzucić ślad stosu, albo gorzej, zjeść.
corlettk

10

Czy to nie jest dokładnie równoważne z brakiem obsługi wyjątków?

Nie do końca, to nie to samo. Resetuje śledzenie stosu wyjątku. Chociaż zgadzam się, że jest to prawdopodobnie błąd, a zatem przykład złego kodu.


8

Nie chcesz rzucać ex - ponieważ spowoduje to utratę stosu wywołań. Zobacz Obsługa wyjątków (MSDN).

I tak, try ... catch nie robi nic pożytecznego (poza utratą stosu wywołań - tak naprawdę jest gorzej - chyba że z jakiegoś powodu nie chciałeś ujawniać tych informacji).


Nie tracisz całego stosu wywołań, gdy używasz funkcji rzuć ex, po prostu tracisz część stosu wywołań od punktu, w którym wystąpił wyjątek powyżej stosu wywołań. Ale zachowujesz stos wywołań z metody, która zrzuciła wyjątek do miejsca, w którym go nazwał klient. W rzeczywistości mogą istnieć przypadki użycia, w których można by tego użyć, albo dobrzy ludzie w Microsoft nie pozwoliliby na to. To powiedziawszy, nie użyłem tego. Kolejną kwestią do zapamiętania jest to, że zgłaszanie wyjątków jest drogie. Rób to tylko z bardzo uzasadnionego powodu. Logowanie wydaje mi się uzasadnione itp.
Charles Owen

5

Rzeczą, o której ludzie nie wspominali, jest to, że chociaż języki .NET tak naprawdę nie robią właściwego rozróżnienia, to pytanie, czy należy podjąć działania w przypadku wystąpienia wyjątku i czy rozwiązać go , są tak naprawdę odrębnymi pytaniami. Istnieje wiele przypadków, w których należy podjąć działanie w oparciu o wyjątki, których nie ma nadziei na rozwiązanie, i są przypadki, w których wszystko, co jest konieczne do „rozwiązania” wyjątku, polega na rozwinięciu stosu do określonego punktu - nie są wymagane żadne dalsze działania .

Ze względu na powszechną mądrość, zgodnie z którą należy „łapać” rzeczy, które można „obsłużyć”, wiele kodów, które powinny być podejmowane w przypadku wystąpienia wyjątków, nie działa. Na przykład wiele kodów uzyska blokadę, ustawi tymczasowo „strzeżony” obiekt, który narusza jego niezmienniki, następnie wprowadzi obiekt do legalnego stanu, a następnie zwolni blokadę, zanim ktokolwiek będzie mógł zobaczyć obiekt. Jeśli wystąpi wyjątek, gdy obiekt znajduje się w niebezpiecznie niepoprawnym stanie, powszechną praktyką jest zwolnienie blokady, gdy obiekt nadal znajduje się w tym stanie. Znacznie lepszym wzorcem byłoby posiadanie wyjątku, który występuje, gdy obiekt znajduje się w „niebezpiecznym” stanie, wyraźnie unieważnia blokadę, więc każda kolejna próba jej zdobycia natychmiast się nie powiedzie.

W większości języków .NET jedynym sposobem na wykonanie akcji w oparciu o wyjątek jest kod catch(nawet jeśli wie, że wyjątek nie zostanie rozwiązany), wykonaj dane działanie, a następnie ponownie throw). Innym możliwym podejściem, jeśli kod nie dba o zgłoszony wyjątek, jest użycie okflagi z try/finallyblokiem; ustaw okflagę na falseprzed blokiem i trueprzed wyjściem z bloku i przed wszystkimi, returnktóre znajdują się w bloku. Wewnątrz finallyzałóżmy, że jeśli oknie jest ustawiony, musiał wystąpić wyjątek. Takie podejście jest semantycznie lepsze niż a catch/ throw, ale jest brzydkie i trudniejsze do utrzymania niż powinno być.


5

Może to być przydatne, gdy programujesz funkcje biblioteki lub biblioteki DLL.

Tej struktury przerzucania można użyć do celowego zresetowania stosu wywołań, aby zamiast widzieć wyjątek zgłoszony z pojedynczej funkcji wewnątrz funkcji, wyjątek otrzymujesz od samej funkcji.

Myślę, że jest to po prostu używane, aby zgłoszone wyjątki były czystsze i nie wchodziły w „korzenie” biblioteki.


3

Jednym z możliwych powodów wyłapania jest wyłączenie filtrowania wyjątków znajdujących się głębiej na stosie ( losowy stary link ). Ale oczywiście, jeśli taka była intencja, pojawiłby się tam komentarz.


Nie zrozumiałem, o co ci chodzi, dopóki nie przeczytam linku ... i wciąż nie jestem do końca pewien, o co ci chodzi ... że jestem całkowicie obeznany z VB.NET. Myślę, że to powoduje, że suma jest zgłaszana jako „niespójna”, prawda? ... Jestem WIELKIM fanem metod statycznych .. oprócz tego, że są proste, istnieje mniejsze prawdopodobieństwo niespójności, jeśli oddzielisz ustawienie atrybutów od kodu który wykonuje rzeczywistą pracę. Stos jest „samooczyszczający”.
corlettk,

3
Ludzie oczekują, że kiedy piszą „spróbuj {Foo ();} w końcu {Bar ();}”), że nic nie działa między Foo a Bar. Ale to nie jest prawda; jeśli twój rozmówca dodał filtr wyjątków i nie ma wtrącanego „catch”, a Foo () wyrzuci, to jakiś inny losowy kod od twojego rozmówcy zostanie uruchomiony przed uruchomieniem twojego wreszcie (Bar). Jest to bardzo złe, jeśli złamałeś niezmienniki lub podniosłeś bezpieczeństwo, oczekując, że zostaną one natychmiast przywrócone do normy do końca i żaden inny kod nie zobaczy tymczasowej zmiany.
Brian,

3

Zależy to od tego, co robisz w bloku catch, i czy chcesz przekazać błąd do kodu wywołującego, czy nie.

Możesz powiedzieć, Catch io.FileNotFoundExeption exa następnie użyć alternatywnej ścieżki do pliku lub innej, ale nadal włączać błąd.

Robienie Throwzamiast zamiast Throw Expozwala zachować ślad pełnego stosu. Throw ex ponownie uruchamia śledzenie stosu z instrukcji throw (mam nadzieję, że ma to sens).


3

Podczas gdy wiele innych odpowiedzi dostarcza dobrych przykładów, dlaczego warto złapać powtórzenie wyjątku, wydaje się, że nikt nie wspomniał o scenariuszu „w końcu”.

Przykładem tego jest metoda, w której ustawiasz kursor (na przykład kursor oczekiwania), metoda ma kilka punktów wyjścia (np. If () return;) i chcesz upewnić się, że kursor został zresetowany na koniec metody.

Aby to zrobić, możesz owinąć cały kod w try / catch / wreszcie. Na koniec ustaw kursor z powrotem na prawy kursor. Aby nie zakopać żadnych ważnych wyjątków, wrzuć to do haczyka.

try
{
    Cursor.Current = Cursors.WaitCursor;
    // Test something
    if (testResult) return;
    // Do something else
}
catch
{
    throw;
}
finally
{
     Cursor.Current = Cursors.Default;
}

1
Czy była catchto obowiązkowa część try...finallyhistorii, czy też odgrywa rolę funkcjonalną w tym przykładzie? - Właśnie dwukrotnie sprawdziłem i jestem w stanie używać try {} finally {}bez bloku catch.
Sebi

2

W przykładzie w opublikowanym kodzie nie ma sensu wychwytywać wyjątku, ponieważ nic nie zrobiono w przypadku tego, że jest on ponownie zgłaszany, w rzeczywistości powoduje więcej szkody niż pożytku, ponieważ stos wywołań zostaje utracony .

Złapałbyś jednak wyjątek, aby wykonać logikę (na przykład zamknięcie połączenia sql blokady pliku lub po prostu rejestrowania) w przypadku wyjątku i wrzucić go z powrotem do kodu wywołującego, aby sobie z tym poradzić. Byłoby to bardziej powszechne w warstwie biznesowej niż w kodzie frontonu, ponieważ koder implementujący warstwę biznesową może obsłużyć wyjątek.

Aby powtórzyć iterację: Nie ma sensu łapać wyjątku w opublikowanym przykładzie. NIE rób tak!


1

Przykro nam, ale wiele przykładów „ulepszonego projektu” nadal śmierdzi okropnie lub może być bardzo mylące. Próbowanie {} catch {log; throw} jest całkowicie bezcelowe. Rejestrowanie wyjątków powinno odbywać się w centralnym miejscu wewnątrz aplikacji. wyjątki i tak burzą stos śledzenia, dlaczego nie zarejestrować ich gdzieś w pobliżu granic systemu?

Należy zachować ostrożność, gdy serializujesz kontekst (np. DTO w jednym podanym przykładzie) tylko w komunikacie dziennika. Może łatwo zawierać poufne informacje, które mogą nie być dostępne dla wszystkich osób, które mogą uzyskać dostęp do plików dziennika. A jeśli nie dodasz żadnych nowych informacji do wyjątku, naprawdę nie widzę sensu owijania wyjątków. Dobra stara Java ma w tym sens, wymaga od osoby dzwoniącej, jakich wyjątków należy się spodziewać po wywołaniu kodu. Ponieważ nie masz tego w .NET, owijanie nie przynosi żadnego efektu w co najmniej 80% przypadków, które widziałem.


Dziękuję za twoją myśl Joe. W Javie (i C #, chyba) chciałbym zobaczyć adnotację na poziomie klasy @FaultBoundary, która zmusza WSZYSTKIE wyjątki (w tym niesprawdzone typy wyjątków) do przechwycenia lub zadeklarowania do wyrzucenia. Wykorzystałbym tę adnotację na publicznych interfejsach każdej warstwy architektonicznej. Tak więc interfejs @FaultBoundary ThingDAO nie byłby w stanie przeciekać szczegółów implementacji, takich jak SQLExceptions, NPE lub AIOB. Zamiast tego rejestrowany byłby „przyczynowy” stacktrace i zgłaszany byłby wyjątek DAOSystemException ... Definiuję wyjątek systemowy jako „trwale śmiertelny”.
corlettk,

5
Istnieje wiele powodów, aby łapać, rejestrować, a następnie ponownie rzucać. W szczególności, jeśli metoda z dziennikiem połowu zawiera informacje, które tracisz po wyjściu z metody. Błąd może być obsłużony później, ale nie jest rejestrowany, a utraciłeś informacje o usterkach w systemie.
Andy,

1
W tym miejscu przydatna jest właściwość Data klasy Exception - przechwytująca wszystkie informacje lokalne do ogólnego rejestrowania. Ten artykuł pierwotnie zwrócił na to moją uwagę: blog.abodit.com/2010/03/…
McGuireV10,

1

Oprócz tego, co powiedzieli inni, zobacz moją odpowiedź na powiązane pytanie, które pokazuje, że łapanie i ponowne rzucanie nie jest opcją (jest w VB, ale część kodu można wywołać w C # z VB).


Chociaż ten link może odpowiedzieć na pytanie, lepiej dołączyć tutaj istotne części odpowiedzi i podać link w celach informacyjnych. Odpowiedzi zawierające tylko łącze mogą stać się nieprawidłowe, jeśli połączona strona ulegnie zmianie. - Z recenzji
LHIOUI,

@HamzaLH, zgadzam się, że nie jest to dobrze napisana odpowiedź, ale zawiera informacje odmienne od innych odpowiedzi i pozytywne głosy. Więc nie rozumiem, dlaczego sugerujesz to usunąć? „Krótkie odpowiedzi na dany temat i dające rozwiązanie są nadal odpowiedziami.” Od meta.stackexchange.com/questions/226258/…
Michael Freidgeim

to jest odpowiedź tylko do linku
LHIOUI

1. Odpowiedzi zawierające tylko łącze należy zmienić na komentarze, a nie usuwać. 2. Jest to odniesienie do innego pytania SO, a nie do strony zewnętrznej, która z czasem uważana była za mniejszą. 3. Ma dodatkowy opis, który sprawia, że ​​nie jest to „tylko link” - patrz meta.stackexchange.com/questions/225370/…
Michael Freidgeim

1

Większość odpowiedzi mówi o powtórzeniu scenariusza.

Zamiast wpisywać go w kodzie, rozważ użycie AOP, w szczególności Postsharp.Diagnostic.Toolkit z OnExceptionOptions IncludeParameterValue i IncludeThisArgument


Chociaż ten link może odpowiedzieć na pytanie, lepiej dołączyć tutaj istotne części odpowiedzi i podać link w celach informacyjnych. Odpowiedzi zawierające tylko łącze mogą stać się nieprawidłowe, jeśli połączona strona ulegnie zmianie. - Z recenzji
Tony Dong,

@TonyDong, zgadzam się, że nie jest to dobrze napisana odpowiedź, ale zawiera informacje inne niż inne odpowiedzi i pozytywne głosy. Więc nie rozumiem, dlaczego sugerujesz to usunąć? BTW, link 5 lat później jest nadal aktualny. „Krótkie odpowiedzi na dany temat i dające rozwiązanie są nadal odpowiedziami.” Od meta.stackexchange.com/questions/226258/…
Michael Freidgeim

Stackoverflow ma tylko tę sugestię.
Tony Dong

@ TonyDong, jeśli odpowiedź nie jest absolutnie bezużyteczna, powinieneś wybrać „Wygląda OK”
Michael Freidgeim

0

Ponowne przeglądanie wyjątków za pośrednictwem throw jest przydatne, gdy nie masz określonego kodu do obsługi bieżących wyjątków lub w przypadkach, gdy masz logikę do obsługi określonych przypadków błędów, ale chcesz pominąć wszystkie inne.

Przykład:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException)
{
    if (numberText.ToLowerInvariant() == "nothing")
    {
        Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
    }
    else
    {
        throw;
    }
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

Istnieje jednak również inny sposób , wykorzystując klauzule warunkowe w blokach catch:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException) when (numberText.ToLowerInvariant() == "nothing")
{
    Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

Ten mechanizm jest bardziej wydajny niż ponowne zgłaszanie wyjątku, ponieważ środowisko wykonawcze .NET nie musi odbudowywać obiektu wyjątku przed jego ponownym zgłoszeniem.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.