gpt4 book ai didi

c# - 是否有理由在 Try/Catch 上使用带有 ExceptionThrown 变量的 Try/Finally

转载 作者:太空狗 更新时间:2023-10-29 17:33:15 27 4
gpt4 key购买 nike

我正在细读 .Net Reference Source并在 ButtonBase.cs 中找到了这颗 gem 在第 408 行:

bool exceptionThrown = true;
try
{
OnClick();
exceptionThrown = false;
}
finally
{
if (exceptionThrown)
{
// Cleanup the buttonbase state
SetIsPressed(false);
ReleaseMouseCapture();
}
}

问题是,什么会促使某人使用 exceptionThrown 标志而不是将其写为

try 
{
OnClick();
}
catch
{
SetIsPressed(false);
ReleaseMouseCapture();
throw;
}

它只是风格上的还是我遗漏了一些副作用?

最佳答案

此代码有两个原因。是的,Greg 提到,它不需要重新抛出异常。但这并不是真正的原因。

真正的原因是语义之一。不应使用异常来处理控制流。这是在处理这样一个事实,即如果在按钮中抛出异常,它可以使按钮的视觉状态保持为“按下”。这并不是真正的“处理”异常。这只是在抛出异常时更正视觉问题。

这段代码不关心异常是什么,它也不想捕获所有异常,因为这是不好的做法。此外,代码没有做任何异常......它只是说“嘿,如果我们到达函数的末尾,那么我们都很好。如果我们没有,那么让我们重置按钮状态只是为了确定”。

因此,这不是真正的异常处理,因此它不会捕获异常。它只是注意到抛出了异常并进行了一些清理。

编辑:

这个方法可能没有那么多争议,如果像这样简单地重命名它并删除任何对异常的引用,它会更有意义:

bool cleanupRequired = true;
try
{
OnClick();
cleanupRequired = false;
}
finally
{
if (cleanupRequired)
{
// Cleanup the buttonbase state
SetIsPressed(false);
ReleaseMouseCapture();
}
}

编辑:

为了支持我下面的评论,我编写了以下测试程序来测试场景:

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; 重新抛出异常时,它不会简单地传递现有异常,它必须重新创建异常并重新抛出它,花费两倍的时间。

正如我们所看到的,捕获异常和不捕获异常之间没有显着差异,但使用 finally。然而,重新抛出异常是成本的来源。

这是在 VS 2012 Update 3 中运行的。

编辑:

没有调试器的计时。如您所见,重新抛出的代价仍然是原来的两倍:

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

关于c# - 是否有理由在 Try/Catch 上使用带有 ExceptionThrown 变量的 Try/Finally,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18798364/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com