Поговорка гласит, что исключения обходятся дорого, когда их ловят, а не бросают. Это связано с тем, что большинство сбора метаданных исключений (например, получение трассировки стека и т. Д.) Действительно происходит только на стороне try-catch (не на стороне throw).
Развертывание стека на самом деле довольно быстрое - CLR поднимается вверх по стеку вызовов и обращает внимание только на найденные им блоки finally; ни в одной точке чистого блока try-finally среда выполнения не пытается «завершить» исключение (это метаданные и т. д.).
Из того, что я помню, любые попытки получения с фильтрами (такие как "catch (FooException) {}") столь же дороги - даже если они ничего не делают за исключением.
Рискну сказать, что метод (назовите его CatchesAndRethrows) со следующим блоком:
try
{
ThrowsAnException();
}
catch
{
throw;
}
Может привести к более быстрому обходу стека в методе, например:
try
{
CatchesAndRethrows();
}
catch (Exception ex) // The runtime has already done most of the work.
{
// Some fancy logic
}
Некоторые цифры:
With: 0.13905ms
Without: 0.096ms
Percent difference: 144%
Вот тест, который я запустил (помните, режим выпуска - запустите без отладки):
static void Main(string[] args)
{
Stopwatch withCatch = new Stopwatch();
Stopwatch withoutCatch = new Stopwatch();
int iterations = 20000;
for (int i = 0; i < iterations; i++)
{
if (i % 100 == 0)
{
Console.Write("{0}%", 100 * i / iterations);
Console.CursorLeft = 0;
Console.CursorTop = 0;
}
CatchIt(withCatch, withoutCatch);
}
Console.WriteLine("With: {0}ms", ((float)(withCatch.ElapsedMilliseconds)) / iterations);
Console.WriteLine("Without: {0}ms", ((float)(withoutCatch.ElapsedMilliseconds)) / iterations);
Console.WriteLine("Percent difference: {0}%", 100 * withCatch.ElapsedMilliseconds / withoutCatch.ElapsedMilliseconds);
Console.ReadKey(true);
}
static void CatchIt(Stopwatch withCatch, Stopwatch withoutCatch)
{
withCatch.Start();
try
{
FinallyIt(withoutCatch);
}
catch
{
}
withCatch.Stop();
}
static void FinallyIt(Stopwatch withoutCatch)
{
try
{
withoutCatch.Start();
ThrowIt(withoutCatch);
}
finally
{
withoutCatch.Stop();
}
}
private static void ThrowIt(Stopwatch withoutCatch)
{
throw new NotImplementedException();
}