我试图更多地了解各种设计选择的含义,并找到最有效的解决方案来防止我的代码中的错误。在深入研究之前,请允许我简要地说一下我的问题:
与if和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];
}
正如您可以清楚地看到的那样,当从world-grid的节点数组(tile)中检索节点时,我有几个if语句以避免出现异常异常。这是最有效的解决方案吗?我可以删除if&#39;而是将返回放在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
}
}
此解决方案正常运行,但有一些原因我不知道这会降低效率吗?我相信它是一个更智能的解决方案的逻辑是,我每次调用该方法时最多可以删除四次比较。考虑到程序实际发送的价值超出限制范围的情况很少见,这似乎是一个很好的权衡。但我不知道的是,异常是如何在幕后工作的。检查异常是否与手动检查值一样昂贵?
更新
在阅读完回复后,我现在对这个主题有了更好的理解。我已经对我的代码进行了一些测试,以解决运行1000万次迭代的各种情况。
根据我的一般假设,如果我们假设永远不会出现输入导致异常的情况,那么try catch块确实更快。但是,在大约10%的方法调用引发异常的情况下,性能会慢5倍以上。我测试了各种百分比,似乎在我的情况下,更好的性能阈值接近1%。
到目前为止,我还不确定有多少百分比的电话确实会引发异常,但我相信这个数字远远低于1%。因此,我可以安全地,除非进一步测试显示,否则使用try-catch块来确保我的代码运行时没有致命错误。
感谢所有贡献者。
答案 0 :(得分:3)
对于不常见的事情例外,例如连接问题,xml-File不是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);
}
除了抛出异常,您还可以返回一个布尔值:
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;
}
效果测试:使用虚假凭据进行10000次尝试:
抛出异常(不显示消息框):181990454 ticks
返回布尔值:644 ticks
我们只是应用程序的一层,因此没有太多的堆栈跟踪要生成。我想你可以看到并特别感受到差异。