tg-me.com/csharp_1001_notes/710
Last Update:
Дан код:
using System;
using System.Runtime.ExceptionServices;
class Program
{
static void Main()
{
try
{
Console.WriteLine(Foo());
}
catch (Exception ex)
{
Console.WriteLine($"Catch: {ex.Message}");
}
}
static int Foo()
{
try
{
return Bar();
}
finally
{
throw new Exception("finally in Foo");
}
}
static int Bar()
{
try
{
throw new Exception("error in Bar");
}
finally
{
Console.WriteLine("Bar finally executed");
}
}
}
Вопросы:
• Что напечатает программа и почему?
• В каком порядке выполняются блоки try / finally?
• Какая из двух ошибок дойдёт до catch, а какая потеряется?
• Как изменить код, чтобы не терять информацию о первой ошибке?
Разбор:
• Bar бросает Exception("error in Bar"). Прежде чем исключение покинет метод, выполняется его finally, выводя Bar finally executed.
• Управление переходит в Foo. Там срабатывает finally, который бросает новое исключение ("finally in Foo").
• По правилам CLR новое исключение из finally заменяет текущее. Первая ошибка пропадает.
• В Main перехватывается только «finally in Foo».
Консольный вывод:
Bar finally executed
Catch: finally in Foo
Как сохранить обе ошибки
Обернуть второе исключение так, чтобы первая причина не потерялась, например:
finally
{
var pending = new Exception("finally in Foo");
throw new AggregateException("Foo failed", pending);
}
или переслать исходное исключение через ExceptionDispatchInfo:
Exception pending = null;
static int Foo()
{
try
{
return Bar();
}
catch (Exception ex)
{
pending = ex; // сохраняем первую причину
throw;
}
finally
{
if (pending != null)
ExceptionDispatchInfo.Capture(pending).Throw();
}
}```
Так ни одна ошибка не будет потеряна, а отладка станет нагляднее.