Причина этого кода - в два раза. Да, говорит Грег, это не требует повторного исключения. Но на самом деле это не причина.
Настоящая причина - одна из семантики. Исключения не должны использоваться для управления потоком управления. То, что это делает, имеет дело с тем, что если исключение выбрасывается внутри кнопки, оно может оставить визуальное состояние кнопок «нажатым». Это не значит «обрабатывать» исключение. Это просто исправление визуальной проблемы в случае исключения исключения.
Этот код не заботится о том, что такое исключение, и он не хочет улавливать все исключения, потому что это плохая практика. Кроме того, код ничего не делает с исключением .. он просто говорит: «Эй, если мы дошли до конца функции, тогда мы все хорошо. Если бы мы этого не сделали, то давайте сбросим состояние кнопки только до быть уверенным".
Итак, это не настоящая обработка исключений, поэтому она не вызывает исключения. Он просто замечает, что было исключено исключение и выполняет некоторую очистку.
EDIT:
Этот метод может быть менее спорным, и сделать гораздо больше смысла, если бы он был просто переименован, как это, удаляя любые ссылки на исключение:
bool cleanupRequired = true;
try
{
OnClick();
cleanupRequired = false;
}
finally
{
if (cleanupRequired)
{
// Cleanup the buttonbase state
SetIsPressed(false);
ReleaseMouseCapture();
}
}
EDIT:
Чтобы поддержать мой комментарий ниже, я написал следующую тестовую программу для тестирования сценариев:
static void Main(string[] args)
{
TimeSpan ts = new TimeSpan();
TimeSpan ts2 = new TimeSpan();
TimeSpan ts3 = new TimeSpan();
TimeSpan ts4 = new TimeSpan();
TimeSpan ts5 = new TimeSpan();
TimeSpan ts6 = new TimeSpan();
TimeSpan ts7 = new TimeSpan();
TimeSpan ts8 = new TimeSpan();
Stopwatch sw = new Stopwatch();
// throw away first run
for (int i = 0; i < 2; i++)
{
sw.Restart();
try
{
throw new NotImplementedException();
}
catch
{
ts = sw.Elapsed;
}
sw.Stop();
ts2 = sw.Elapsed;
try
{
sw.Restart();
try
{
throw new NotImplementedException();
}
finally
{
ts3 = sw.Elapsed;
}
}
catch
{
ts4 = sw.Elapsed;
}
sw.Stop();
ts5 = sw.Elapsed;
try
{
sw.Restart();
try
{
throw new NotImplementedException();
}
catch
{
ts6 = sw.Elapsed;
throw;
}
}
catch
{
ts7 = sw.Elapsed;
}
sw.Stop();
ts8 = sw.Elapsed;
}
Console.WriteLine(ts);
Console.WriteLine(ts2);
Console.WriteLine(ts3);
Console.WriteLine(ts4);
Console.WriteLine(ts5);
Console.WriteLine(ts6);
Console.WriteLine(ts7);
Console.WriteLine(ts8);
Console.ReadLine();
}
И я получил следующие результаты (я разделить их друг от друга, чтобы сделать их более удобными для чтения):
00:00:00.0028424
00:00:00.0028453
00:00:00.0028354
00:00:00.0028401
00:00:00.0028427
00:00:00.0028404
00:00:00.0057907
00:00:00.0057951
Последние 3 показывают, что при Повторное выбрасывание исключения используя throw;
, он не просто передает существующее исключение, он должен воссоздать исключение и переустановить его, взяв в два раза больше.
Как мы видим, нет существенной разницы между улавливанием исключения и не ловлей, а использованием, наконец,. Тем не менее, повторное исключение - это то, где стоимость.
Это работает в VS 2012 Update 3.
EDIT:
Задержки без отладчика. Как вы можете видеть, Повторное выбрасывание еще в два раза дороже:
00:00:00.0000149
00:00:00.0000154
00:00:00.0000137
00:00:00.0000140
00:00:00.0000146
00:00:00.0000137
00:00:00.0000248
00:00:00.0000251
Похоже, было бы нормально проверить определенные пользовательские бизнес-исключения во время улова, чтобы вы могли сделать что-то еще. Это выглядит в значительной степени, чтобы разоблачить стек ни за что. пустая попытка {} catch {} хуже, чем бросок по значимым причинам, и вы просто разрушаете стек за этим. –
Я думаю, что между ними нет никакой разницы. Однако, если вы пишете что-то подобное, поскольку код будет меняться сверхурочно, в какой-то момент вам понадобится информация из исключения, и вы в конечном итоге используете catch. Однако небольшие изменения. –