Cab*_*ose 4 c# if-statement try-catch
我试图更多地了解各种设计选择的含义,并找到最有效的解决方案来防止我的代码中出现错误。在深入探讨之前,请允许我简要概括地陈述我的问题:
与 if 语句结构相比,try catch 块是处理越界异常的更有效解决方案吗?
我知道引发异常很昂贵,但是通过删除不必要的 if 语句来降低成本吗?
现在,请允许我陈述我的具体问题,以便为您提供更多有用的信息。
我正在构建一个游戏,该游戏的一部分是一个世界网格解决方案和一个探路者。游戏单元可以从世界网格请求节点(通过将坐标信息作为有序对 (x, z) 发送),然后发送到探路者或对它们执行一些其他杂项操作。因为节点被请求的频率很高,特别是探路者,这似乎是一个尝试优化的聪明地方。
这是我当前根据节点数组中的x和z值返回给定节点的代码:
public Node GetTile(int x, int z)
{
if (x < 0)
x = 0;
if (x >= length_X)
x = length_X - 1;
if (z < 0)
z = 0;
if (z >= length_Z)
z = length_Z - 1;
return tiles [x, z];
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我有几个 if 语句来避免在从世界网格的节点(图块)数组中检索节点时出现越界异常。这是最有效的解决方案吗?我可以删除 if 而是将返回放在 try catch 块中,如下所示:
public Node GetTile(int x, int z)
{
try
{
return tiles[x, z];
}
catch (System.IndexOutOfRangeException e)
{
//handle exception here
//do smart programming fix-y stuff
}
}
Run Code Online (Sandbox Code Playgroud)
此解决方案有效,但是否有一些我不知道的原因使其效率降低?我相信它是一个更聪明的解决方案的逻辑是,每次调用该方法时,我都会删除多达四个比较。考虑到程序实际发送超出范围的值的情况很少见,这似乎是一个很好的权衡。我不知道的是,异常在幕后是如何工作的。检查异常是否与手动检查值一样昂贵?
更新:
通读这里的回复后,我现在对这个话题有了更好的理解。我已经对我的代码运行了一些测试,计算了运行 1000 万次迭代的各种情况。
与我的一般假设一致,如果我们假设永远不会出现输入导致异常的情况,那么 try catch 块确实更快。但是,在大约 10% 的方法调用引发异常的情况下,性能会慢 5 倍以上。我测试了各种百分比,似乎在我的案例中获得更好性能的阈值接近 1%。
到目前为止,我不确定实际上有多少调用会引发异常,但我相信这个数字会远低于 1%。因此,除非进一步测试表明,否则我可以安全地使用 try-catch 块来确保我的代码运行时没有致命错误。
感谢所有做出贡献的人。
不常见的情况除外,例如连接问题、xml 文件不是 xml 格式等。
与一些简单的 -if语句相比,异常的性能通常很差,但也有一些情况,异常处理可能比自己检查数据的有效性还要快,特别是如果你不知道如何快速完成(例如检查有效 xml 格式的文件)。
异常的性能取决于您在堆栈中的“深度”。因此,当您在应用程序的第 24 层(可能由拦截器和正常逻辑层引起)时,必须创建大量堆栈跟踪。
您不能对异常的性能给出一般性声明,但是当您可以避免异常时,您应该这样做。正如它们的名字已经说明的那样,它们是为例外而设计的。
一个可以避免异常的小例子:
try
{
LoginUser("Fooooo", "Bar");
}catch(InvalidPasswordException e){
MessageBox.Show(e.Message);
}
private static void LoginUser(string pUsername, string pPassword)
{
if (pUsername != "Foo" || pPassword != "Bar")
throw new InvalidPasswordException("Invalid username and/or password");
GrantAccess(pUsername);
}
Run Code Online (Sandbox Code Playgroud)
除了抛出异常,您还可以只返回一个布尔值:
if (!LoginUser("Fooooo", "Bar"))
{
MessageBox.Show("Invalid username and/or password");
}
private static bool LoginUser(string pUsername, string pPassword)
{
if (pUsername != "Foo" || pPassword != "Bar")
return false;
GrantAccess(pUsername);
return true;
}
Run Code Online (Sandbox Code Playgroud)
性能测试:使用假凭据尝试 10000 次:
投掷Exception(不显示消息框):181990454 滴答
返回boolean:644 滴答
而且我们只是进入应用程序的 1 层,所以没有太多的堆栈跟踪要生成。我想你可以看到并特别感受到其中的不同。