Sprawdzam jakiś kod dla znajomego i mówię, że używał instrukcji return wewnątrz bloku try-wreszcie. Czy kod w sekcji Wreszcie nadal jest uruchamiany, mimo że reszta bloku try nie?
Przykład:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
c#
.net
exception-handling
try-catch
JamesEggers
źródło
źródło
StackOverflowException
,ExecutionEngineException
to tylko niektóre z nich. A ponieważ nie można ich obsłużyć,finally
nie będzie działać.try
bloku. Nic o nagłym przerwaniu programu.try
bloku jestreturn
instrukcją. (Druga instrukcja tego bloku jest nieosiągalna i wygeneruje ostrzeżenie.)Odpowiedzi:
Prosta odpowiedź: tak.
źródło
finally
blok zostanie wykonany.Zwykle tak. W końcu sekcja ma gwarancję wykonania wszystkiego, co się wydarzy, w tym wyjątków lub instrukcji return. Wyjątkiem od tej reguły jest asynchroniczny wyjątek występujący w wątku (
OutOfMemoryException
,StackOverflowException
).Aby dowiedzieć się więcej o wyjątkach asynchronicznych i niezawodnym kodzie w takich sytuacjach, przeczytaj o ograniczonych regionach wykonywania .
źródło
Oto mały test:
Wynik to:
źródło
WriteLine
faktycznym wykonaniem wywołania metody. W tym przypadkureturn
wywołanie ustawia wynik metod, w końcu zapisuje na konsoli - zanim metoda zakończy działanie. NastępnieWriteLine
metoda Main wyrzuca tekst z wywołania zwrotnego.Cytowanie z MSDN
źródło
finally
w rzeczywistości nic nie gwarantuje nawet dla całkowicie zwyczajnych programów (które zdarzyły się rzucić ten wyjątek).Ogólnie tak, w końcu będzie działać.
W przypadku następujących trzech scenariuszy w końcu ZAWSZE uruchomi się:
Obejmuje to wyjątki zgodne z CLS, które pochodzą z System.Exception i wyjątki niezgodne z CLS, które nie pochodzą z System.Exception. Wyjątki niezgodne z CLS są automatycznie pakowane przez wyjątek RuntimeWrappedException. C # nie może zgłaszać wyjątków skarg innych niż CLS, ale języki takie jak C ++ mogą. C # może wywoływać kod napisany w języku, który może zgłaszać wyjątki niezgodne z CLS.
Począwszy od platformy .NET 2.0 wyjątek ThreadAbortException nie będzie już uniemożliwiać ostatecznego uruchomienia. ThreadAbortException jest teraz podnoszony przed lub po końcu. Ostatecznie zawsze będzie działać i nie zostanie przerwane przerwaniem wątku, o ile próba została faktycznie podjęta przed przerwaniem wątku.
Następujący scenariusz ostatecznie nie uruchomi się:
Asynchroniczny wyjątek StackOverflowException.
Od wersji .NET 2.0 przepełnienie stosu spowoduje zakończenie procesu. Ostatecznie nie zostanie uruchomione, chyba że zastosowane zostanie dalsze ograniczenie, aby ostatecznie utworzyć CER (region ograniczonego wykonywania). CER nie powinny być używane w ogólnym kodzie użytkownika. Powinny być używane tylko tam, gdzie krytyczne jest, aby zawsze działał kod czyszczący - po tym wszystkim proces i tak zostanie zamknięty z powodu przepełnienia stosu, a zatem wszystkie zarządzane obiekty będą domyślnie czyszczone. Dlatego jedynym miejscem, w którym powinna być odpowiednia CER, są zasoby przydzielone poza procesem, np. Niezarządzane uchwyty.
Zazwyczaj niezarządzany kod jest pakowany przez niektóre klasy zarządzane, zanim zostanie wykorzystany przez kod użytkownika. Zarządzana klasa opakowania zwykle korzysta z SafeHandle do zawijania niezarządzanego uchwytu. SafeHandle implementuje krytyczny finalizator i metodę Release, która jest uruchamiana w CER, aby zagwarantować wykonanie kodu czyszczenia. Z tego powodu nie powinieneś widzieć CER zaśmieconych przez cały kod użytkownika.
Zatem fakt, że w końcu nie działa na StackOverflowException, nie powinien mieć wpływu na kod użytkownika, ponieważ proces i tak zostanie zakończony. Jeśli masz przypadek na krawędzi, w którym musisz wyczyścić niektóre niezarządzane zasoby, poza SafeHandle lub CriticalFinalizerObject, użyj CER w następujący sposób; ale należy pamiętać, że jest to zła praktyka - niezarządzana koncepcja powinna zostać wyodrębniona do klas zarządzanych i odpowiednich SafeHandle z założenia.
na przykład,
źródło
FailFast
wewnętrznie. Jedynym sposobem, w jaki udało mi się je złapać, jest dostosowanie środowiska uruchomieniowego CLR . Zauważ, że twój punkt jest nadal ważny dla niektórych innych wyjątków asynchronicznych.Jest bardzo ważny wyjątek od tego, o którym nie wspomniałem w żadnej innej odpowiedzi, i który (po programowaniu w C # przez 18 lat) nie mogę uwierzyć, że nie wiedziałem.
Jeśli rzucisz lub wywołać wyjątek dowolny w swoim
catch
bloku (nie tylko dziwnymStackOverflowExceptions
i tym podobnym) i nie masz całegotry/catch/finally
bloku w innymtry/catch
bloku, twójfinally
blok się nie wykona. Łatwo to wykazać - i gdybym sam tego nie widział, biorąc pod uwagę, jak często czytałem, że to naprawdę dziwne, małe, narożne przypadki, które mogą spowodować, żefinally
blok nie zostanie wykonany, nie uwierzyłbym.Jestem pewien, że istnieje ku temu powód, ale to dziwne, że nie jest szerzej znany. (Zostało to odnotowane na przykład tutaj , ale nigdzie w tym konkretnym pytaniu).
źródło
finally
blok po prostu nie jestcatch
blokiem dla bloku.Zdaję sobie sprawę, że jestem spóźniony na imprezę, ale w scenariuszu (różniącym się od przykładu OP), w którym rzeczywiście zgłaszane są wyjątki stany MSDN ( https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ): „Jeśli wyjątek nie zostanie przechwycony, wykonanie bloku w końcu zależy od tego, czy system operacyjny zdecyduje się uruchomić operację cofania wyjątku.”
Ostatecznie blok ma gwarancję wykonania tylko wtedy, gdy jakaś inna funkcja (taka jak Main) w górę stosu wywołań wyjątku. Ten szczegół zwykle nie stanowi problemu, ponieważ wszystkie środowiska wykonawcze (CLR i OS) programy C # działają na wolnych zasobach, które większość procesów posiada po wyjściu (uchwyty plików itp.). W niektórych przypadkach może to być kluczowe: Operacja bazy danych w połowie, którą chcesz zatwierdzić. rozwijać; lub niektóre zdalne połączenie, które może nie zostać automatycznie zamknięte przez system operacyjny, a następnie zablokuje serwer.
źródło
Tak. To jest właśnie główny punkt ostatecznego stwierdzenia. O ile nie wydarzy się coś katastroficznego (brak pamięci, komputer niepodłączony itp.), Należy zawsze wykonać instrukcję w końcu.
źródło
finally
bloku, jeśli wyjątek ten nigdy nie zostanie złapany. Zaskoczyło mnie to ;-).Nie będzie również uruchamiany w przypadku nieprzechwyconego wyjątku i działania w wątku hostowanym w usłudze Windows
Wreszcie nie jest wykonywany, gdy działa w wątku w usłudze systemu Windows
źródło
w końcu nie będzie działać, jeśli wychodzisz z aplikacji przy użyciu System.exit (0); jak w
wynik byłby po prostu: spróbuj
źródło
c#
, ale wydaje się, że takJava
. A poza tym w większości przypadkówSystem.exit()
jest ślad złego projektu :-)99% scenariuszy gwarantuje, że kod wewnątrz
finally
bloku będzie działał, jednak pomyśl o tym scenariuszu: masz wątek, który matry
->finally
blok (niecatch
) i otrzymujesz nieobsługiwany wyjątek w tym wątku. W takim przypadku wątek zostanie zamknięty, a jegofinally
blok nie zostanie wykonany (w tym przypadku aplikacja może nadal działać)Ten scenariusz jest dość rzadki, ale ma on jedynie na celu pokazanie, że odpowiedź ZAWSZE nie brzmi „tak”, najczęściej jest to odpowiedź „tak”, a czasami w rzadkich przypadkach „nie”.
źródło
Głównym celem wreszcie bloku jest wykonanie tego, co jest w nim zapisane. Nie powinno to zależeć od tego, co dzieje się podczas try lub catch. Jednak z System.Environment.Exit (1) aplikacja zakończy działanie bez przejścia do następnego wiersza kodu.
źródło