【问题标题】:How to decide between using if/else vs try/catch?如何在使用 if/else 与 try/catch 之间做出决定?
【发布时间】:2011-09-05 09:25:42
【问题描述】:

在编写代码时,如何决定使用 if/else 还是 try/catch?例如,在检查文件时,应该基于 if/else (if (File.Exists)) 还是 try/catch 块?

例如,写入文件可以通过 if/else 块来创建文件然后写入文件,或者假设文件存在的 try/catch 来处理。选择时有哪些注意事项?

谢谢

【问题讨论】:

  • 这是一个相当糟糕的问题,因为这两个项目在您的代码中的用途完全不同。这就像在说“我应该坐汽车还是直升机?”根据您要执行的操作,答案会发生变化。在给出的示例中,仍应使用两者。

标签: c#


【解决方案1】:

异常处理只应在异常情况下进行或使用。

在取决于文件是否存在的情况下,如果您可以简单地使用 try catch 块是没有意义的

if(File.Exists(path))
{
}
else
{

}

异常处理会导致很多性能损失,因此请尝试通过在代码中应用更多检查来尽量减少异常情况,例如 if File.Exists(path))

【讨论】:

  • 我在这里不会感到安全。我猜有些情况下文件存在,但由于正在使用或某些原因无法打开?
【解决方案2】:

当文件预计不存在时,首先检查是否存在。但是当丢失的文件是异常状态时,您应该用异常来指示这种异常状态。

所以基本思路是: 尽量避免在可预期的情况下出现例外情况。

【讨论】:

    【解决方案3】:

    如果您认为操作正常应该成功,那么try/catch 可以更容易阅读。特别是,如果有很多失败原因(多个catch 块)。

    否则,如果它有时成功有时失败 - 并且出于特定原因这样做,请使用 if/else(这称为结构化异常处理)。

    有些人指出使用try/catch 处理异常可能非常耗时。我倾向于按照以下思路阅读这样的建议:如果您的分析表明存在性能问题,请不要在紧密的内部循环中执行此操作。在编写初稿时,根本不用考虑在此级别进行优化!

    【讨论】:

    • +1。另外,当异常被抛出时,异常处理通常不是更快吗?
    • @Macke:我很确定它很快,并且只有在您必须展开异常堆栈时才会变慢,但是我不会打赌它会比一个条件。我从来没有费心去看看这是怎么做到的。也许我们都应该去研究一些编译器/解释器的源代码,等我们完成后再回来?
    【解决方案4】:

    你不应该使用 try/catch 来控制流。

    生成异常是一项极其昂贵的操作。 if/else 更快更干净。

    【讨论】:

    • 打开文件不仅仅是控制流程...可能会发生异常情况。
    • 但是,在处理文件时,您必须处理不同的问题。例如,您想要确定操作失败是因为文件被锁定还是因为它根本不存在。此外,您可以提供合理的默认值(即创建文件)。
    • 生成异常可能代价高昂,但如果您确信异常情况几乎永远不会发生,那么 if-else 实际上会慢一些。请参阅下面的答案,在那里我进行了测试,看看如果异常/其他情况永远不会发生,哪个更快。
    • 永远不要说永远。尝试 Catch 检查文件是否存在比 File.Exists 快得多。事实上,随着文件夹变得越来越大,File.Exists 的速度比 Try Catch 的速度增加得快得多。在检查 Window XP 上是否存在文件时,try-catch 可以更快。 Windows 7 在处理高度密集的目录时表现得更好,Win 8 甚至更好。但是对于 XP,try catch 要好得多。
    • Try/catch 默认是一个流控制语句。因此,您在答案中的第一个陈述是无效的。除此之外,我个人认为如果可能的话应该首选 if/else 语句,尽管事实上 c# 在设计上是一种异常驱动的错误处理语言。
    【解决方案5】:

    通常取决于

    对于基于文件的内容,您几乎总是想尝试操作并处理故障,而不是先检查。原因是文件系统是共享资源,您不能保证在 file.exists 返回 true 后文件确实存在,因为其他进程可能同时删除了它。

    【讨论】:

      【解决方案6】:

      在处理文件时,您应该始终使用 try/catch,因为文件的状态可能会在您的程序之外发生变化。

      考虑以下代码位:

      if(File.Exists("file.txt"))
          File.Delete("file.txt")
      

      在 if 语句之后,Delete() 调用之前,该文件可能已被另一个进程删除。当您尝试删除它时,会引发异常。

      在处理文件时,还有很多事情需要考虑,您可能无法通过 ifs 捕捉到,例如文件位于不可用的网络连接上、访问权限发生变化、硬盘故障等.

      这些事情不在你的程序的控制范围内,所以你应该有异常处理程序。

      【讨论】:

        【解决方案7】:

        通常你应该两者都做。 try/catch 以避免异常情况(文件突然从另一个线程中删除)。和 if/else 处理非异常(检查文件是否存在)。 Try/catch 比通常的 if/else 相对慢,因此不值得将它用于所有事情。

        【讨论】:

          【解决方案8】:

          当可能发生意外(异常)并且您想对其做一些特别的事情时,您会使用 try/catch,例如:

          try
          {
             //Do something that might rise an exception, say a division by 0
             //this is just an easy example as you might want to check if said value is not 0
             //before dividing
             int result = someNumberOfMine / anUnsafeNumber;
          }
          catch
          {
             //if something unexpected happened, do a special treament
          }
          

          在您的特定情况下,我建议使用 File.Exists 来验证文件的存在,而不是使用 try/catch 块,因为可以在对其进行任何操作之前检查文件的存在与否。

          【讨论】:

            【解决方案9】:

            正如一些答案已经指出的那样,这取决于。

            if/else 用于流控制,但带有捕获发生错误的附加加号的异常也可以。但正如 Turowicz 指出的那样,对很多人来说,使用 try/catch 超过最低限度是一种不好的做法。

            您总是可以从Ned Batchelder(谈论返回码,作为使用异常的替代方法)和Joel Spolsky(为什么他不喜欢使用异常进行编程)阅读这些文章,以了解其他人的想法例外,然后自己决定。

            【讨论】:

            • 很好的链接!引用其中一个 cmets 的一部分(由 Ray Trend 撰写):“通常有 10 种人,一种以二进制方式思考的人,另一种不……哎呀,抛出 XInappropriateMetaphor”。与有选择的 C++ 不同,在 C# 中我们必须处理异常。两种方法都有优点和缺点。又一次,工具只是工具。它们的有效性取决于用户...
            【解决方案10】:

            在做出此类决定时,“例外应该是例外”这句格言很有用。原则是您应该使用标准程序流程(即 if 语句)处理已知情况,以便异常代表意外情况(即错误)。

            当然,就像任何规则一样,它是要被打破的。

            另外,我不会太担心异常处理对性能的影响。除了极端情况外,开销几乎可以忽略不计。

            【讨论】:

              【解决方案11】:

              只是一个想法...其中一个答案是,例如,如果您有被零除的可能性,您应该尝试捕获。我想知道为什么?你在这里可以控制,你可以在分裂之前检查,然后采取行动。如果为零,则不需要进行除法,而是执行另一个逻辑。

              我只会在您无法控制或无法(或没有意义)事先检查(打开文件,...)的情况下使用 try catch。

              在你的情况下,我会使用 File.Exists 和 try/catch。 File.Exists 作为业务检查(不存在时无需打开),try/catch 捕捉打开文件时可能出现的任何异常。

              【讨论】:

                【解决方案12】:

                为此,您知道文件退出问题。所以你更喜欢if else。

                如果不知道问题,最好使用try catch。

                我建议两者,如下所示

                try 
                {
                  if(File.Exists(path)) 
                  { 
                     do work
                  } 
                  else 
                  {
                     messagebox.show("File Path Not Exit");
                  } 
                }
                catch(Exception e) 
                {
                 messagebox.show(e); 
                }
                

                它会捕获所有我们没有想到的错误。

                【讨论】:

                • +1 表示故障安全代码,但该示例是多余的。 if 语句与 try/catch 完全一样,仅针对一个特定实例。 MessageBox.Show(e.Message) 无论如何都会返回消息“文件不存在”。我建议用有意义的东西重写它。
                【解决方案13】:

                只是为了解决这个问题(是的,这个问题是 8 个月前提出的,但互联网总是知道的!),我决定运行一个小测试,如果 如果 em> 你很确定你不会有例外——例如,“其他”部分只会发生 0.001% 的时间。事实证明,如果你从不必须捕获/其他任何东西,try-catch 的速度大约快 4%(无论如何,在我的机器上)。这是代码和随附的结果:

                案例 1:if-else:

                var startTime = DateTime.Now;
                int bazillion = 100000000;
                int[] list = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
                for (int i = 0; i < bazillion; i++)
                {
                    for (int k = 0; k < list.Length; k++)
                    {
                        if (k >= 0)
                        {
                            list[k] = i;
                        }
                        else
                        {
                            // do nothing.
                        }
                    }
                }
                var executionTime = DateTime.Now - startTime;
                Debug.WriteLine (executionTime.TotalMilliseconds);
                

                5 次运行的执行时间(毫秒):7441.4256、7392.4228、7545.4316、7531.4308、7323.4188。
                平均 = 7446.82592 毫秒


                案例 2:try-catch:

                var startTime = DateTime.Now;
                int bazillion = 100000000;
                int[] list = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
                for (int i = 0; i < bazillion; i++)
                {
                    for (int k = 0; k < list.Length; k++)
                    {
                        try
                        {
                            list[k] = i;
                        }
                        catch (Exception e)
                        {
                            // do nothing
                        }
                    }
                }
                var executionTime = DateTime.Now - startTime;
                Debug.WriteLine(executionTime.TotalMilliseconds);
                

                5 次运行的执行时间(毫秒):7258.4152、7137.4083、7070.4044、7052.4033、7120.4073 平均 = 7127.8077 毫秒


                结论 (基于这个相当简单的例子;实际里程可能会有所不同,等等)
                就绝对数字而言,if 您非常确定不会发生异常/其他情况,try-catch 比每次都必须执行“if”子句快 4% .

                【讨论】:

                • 当然,如果您确实预计会发生异常,我完全同意通过 if-else 处理它的其他响应(至少是初步的文件存在检查)效率更高。这是我偶然发现的一篇文章,它强调了差异有多大http://www.dotnetexpertguide.com/2011/12/efficiencies-use-of-try-catch-block.html
                • 除了你所说的之外,这种分析结果取决于这个测试是在代码的调试版本还是发布版本上完成的。代码优化使 if 语句更快。
                • 我也进行了类似于迈克尔的测试。我在 Release 版本上进行了测试。我得到了可比较的结果。但我更进了一步,包括一个测试 try/catch Failure 以查看 catch 花费多长时间。捕获异常实际上比简单地点击 Else 语句慢 1000 倍。
                【解决方案14】:

                从所有答案中都可以明显看出,没有标准/认可的方式来决定您是否应该使用其中一种。如果操作正确,这两种方法都会有效。如果做得不正确,这两种方法都将是低效的。

                我更喜欢有意义的 if/else 语句(即在我自己的函数中),而当我调用我无法控制的函数时,我更喜欢 Try 块。

                在上面的例子中,如果你控制了文件,File.Exists() 就足够了(意味着没有其他程序可能会操纵它),但如果文件有可能在检查和使用之间消失,那就不够了.

                根据我的经验,在大多数情况下,文件操作通常会更好地处理异常,因为这些文件操作在 c# 中会引发异常。它们不返回可以使用 if 语句检查的错误代码。

                【讨论】:

                  【解决方案15】:

                  当您在执行之前已经可以处理某种情况时,您应该使用 if-else。但是,如果您在实际执行之前无法知道某件事是否会起作用,请使用 try-catch。

                  案例 1:Try-Catch 的有效使用

                  boolean isNumber(String input) {
                      try {
                          Integer.parseInt(input);
                          return true;
                      } catch (NumberFormatException) {
                          return false;
                      }
                  }
                  

                  在您真正“尝试”解析它之前,您无法知道输入是否是一个数字。因此,请使用 try-catch。

                  案例 2:if-else 的有效使用

                  boolean isNotNull(Object o) {
                      if (o != null) {
                          return true;
                      } else {
                          return false;
                      }
                  }
                  

                  我可以知道一个对象在调用它的方法之前是空的。因此,请使用 if-else。

                  案例 3:当 if-else 可以满足时,try-catch 的使用无效

                  boolean isNotNull(Object o) {
                      try {
                          // Some operation of object to know it's not null
                          o.hashCode();
                          return true;
                      } catch (NullPointerException e) {
                          return false;
                      }
                  }
                  

                  提示:使用 if-else 作为应用程序的保护措施,例如检查空值、处理边缘情况等。要定义不同的应用程序流程,请使用多态性来进行更好的状态管理。

                  【讨论】:

                    猜你喜欢
                    • 2017-04-07
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-10-26
                    相关资源
                    最近更新 更多