try {
// Do stuff
}
catch (Exception e) {
throw;
}
finally {
// Clean up
}
Kiedy w powyższym bloku wywoływany jest ostatni blok? Przed rzuceniem e, czy w końcu zostaje sprawdzony, a następnie złapany?
try {
// Do stuff
}
catch (Exception e) {
throw;
}
finally {
// Clean up
}
Kiedy w powyższym bloku wywoływany jest ostatni blok? Przed rzuceniem e, czy w końcu zostaje sprawdzony, a następnie złapany?
Odpowiedzi:
Zostałby wywołany po ponownym wyrzuceniu e (tj. Po wykonaniu bloku catch)
edytowanie tego 7 lat później - jedną ważną uwagą jest to, że jeśli enie zostanie przechwycony przez blok try / catch wyżej na stosie wywołań lub obsługiwany przez globalną procedurę obsługi wyjątków, finallyblok może w ogóle nie zostać wykonany.
finallyNIE jest wykonywany, jeśli wyjątek rzucony w poprzednim catchnigdy nie został przechwycony w zewnętrznym try- catchbloku!
Dlaczego nie spróbować:
outer try
inner try
inner catch
inner finally
outer catch
outer finally
z kodem (sformatowany dla spacji pionowej):
static void Main() {
try {
Console.WriteLine("outer try");
DoIt();
} catch {
Console.WriteLine("outer catch");
// swallow
} finally {
Console.WriteLine("outer finally");
}
}
static void DoIt() {
try {
Console.WriteLine("inner try");
int i = 0;
Console.WriteLine(12 / i); // oops
} catch (Exception e) {
Console.WriteLine("inner catch");
throw e; // or "throw", or "throw anything"
} finally {
Console.WriteLine("inner finally");
}
}
outer try inner try inner catch Unhandled Exception: System.DivideByZeroException...
Po przeczytaniu wszystkich odpowiedzi tutaj wygląda na to, że ostateczna odpowiedź to zależy :
Jeśli ponownie wyrzucisz wyjątek w bloku catch, a ten wyjątek zostanie przechwycony w innym bloku catch, wszystko zostanie wykonane zgodnie z dokumentacją.
Jeśli jednak wyjątek ponownie wywołany jest nieobsługiwany, ostatecznie nigdy nie jest wykonywany.
Przetestowałem ten przykład kodu w VS2010 w / C # 4.0
static void Main()
{
Console.WriteLine("Example 1: re-throw inside of another try block:");
try
{
Console.WriteLine("--outer try");
try
{
Console.WriteLine("----inner try");
throw new Exception();
}
catch
{
Console.WriteLine("----inner catch");
throw;
}
finally
{
Console.WriteLine("----inner finally");
}
}
catch
{
Console.WriteLine("--outer catch");
// swallow
}
finally
{
Console.WriteLine("--outer finally");
}
Console.WriteLine("Huzzah!");
Console.WriteLine();
Console.WriteLine("Example 2: re-throw outside of another try block:");
try
{
Console.WriteLine("--try");
throw new Exception();
}
catch
{
Console.WriteLine("--catch");
throw;
}
finally
{
Console.WriteLine("--finally");
}
Console.ReadLine();
}
Oto wynik:
Przykład 1: rzut ponownie do wnętrza innego bloku try:
--outer try
---- wewnętrzna próba
---- wewnętrzna złapanie
---- wewnętrzna ostatecznie -
zewnętrzna złapanie -
router wreszcie
Huzzah!Przykład 2: ponowne wyrzucenie poza inny blok try:
--try
--catchNieobsługiwany wyjątek: System.Exception: zgłoszono wyjątek typu „System.Exception”.
w ConsoleApplication1.Program.Main () w C: \ local source \ ConsoleApplication1 \ Program.cs: wiersz 53
Twój przykład zachowałby się identycznie jak ten kod:
try {
try {
// Do stuff
} catch(Exception e) {
throw e;
}
} finally {
// Clean up
}
Na marginesie, jeśli naprawdę masz na myśli throw e;(to znaczy wyrzuć ten sam wyjątek, który właśnie złapałeś), znacznie lepiej jest po prostu to zrobić throw;, ponieważ zachowa to oryginalny ślad stosu zamiast tworzyć nowy.
finallyblok będzie działał po catchbloku (nawet jeśli blok catch ponownie zgłosi wyjątek), co próbuje zilustrować mój fragment kodu.
trybloku moja odpowiedź ma „spróbuj-złapać”. Próbuję wyjaśnić zachowanie konstrukcji trzyczęściowej za pomocą dwóch konstrukcji dwuczęściowych. Nie widzę żadnego znaku drugiego trybloku w oryginalnym pytaniu, więc nie rozumiem, skąd to rozumiesz.
Jeśli w bloku obsługi catch znajduje się nieobsługiwany wyjątek, ostatni blok zostanie wywołany dokładnie zero razy
static void Main(string[] args)
{
try
{
Console.WriteLine("in the try");
int d = 0;
int k = 0 / d;
}
catch (Exception e)
{
Console.WriteLine("in the catch");
throw;
}
finally
{
Console.WriteLine("In the finally");
}
}
Wynik:
C: \ users \ administrator \ documents \ TestExceptionNesting \ bin \ Release> TestExceptionNesting.exe
w próbie
w połowie
Nieobsługiwany wyjątek: System.DivideByZeroException: próbowano podzielić przez zero. at TestExceptionNesting.Program.Main (String [] args) w C: \ users \ administrator \ documents \ TestExceptionNesting \ TestExceptionNesting.cs: wiersz 22
C: \ users \ administrator \ documents \ TestExceptionNesting \ bin \ release>
Zadano mi to pytanie dzisiaj na wywiadzie, a ankieter ciągle powtarzał: „Czy na pewno w końcu nie zostanie wezwany?” Nie byłem pewien, czy chodziło o podchwytliwe pytanie, czy ankieter miał na myśli coś innego i napisał niewłaściwy kod do debugowania, więc wróciłem do domu i wypróbowałem go (kompilacja i uruchomienie, bez interakcji z debugerem), tylko po to, żeby się skupić reszta.
Testowanie za pomocą aplikacji konsoli C #, ostatecznie kod został wykonany po rzuceniu wyjątku: istniało „Okno dialogowe błędu aplikacji” i po wybraniu opcji „Zamknij program” ostatni blok został wykonany w tym oknie konsoli. Ale ustawiając punkt krytyczny wewnątrz ostatniego bloku kodu, nigdy nie mogę tego osiągnąć. Debugger zatrzymuje się na instrukcji throw. Oto mój kod testowy:
class Program
{
static void Main(string[] args)
{
string msg;
Console.WriteLine(string.Format("GetRandomNuber returned: {0}{1}", GetRandomNumber(out msg), msg) == "" ? "" : "An error has occurred: " + msg);
}
static int GetRandomNumber(out string errorMessage)
{
int result = 0;
try
{
errorMessage = "";
int test = 0;
result = 3/test;
return result;
}
catch (Exception ex)
{
errorMessage = ex.Message;
throw ex;
}
finally
{
Console.WriteLine("finally block!");
}
}
}
Debugowanie w VS2010 - .NET Framework 4.0