【问题标题】:What exceptions should I handle我应该处理哪些异常
【发布时间】:2012-04-16 21:47:47
【问题描述】:

我有以下代码:

        public void OpenFile(string FileName)
        {
            if (FileName == null)
                throw new ArgumentNullException("FileName", "OpenFile: Filename is null");


            List<int> readItems = new List<int>();
            using (StreamReader reader = new StreamReader(FileName))
            {
                string line;
                int batchItem;
                while ((line = reader.ReadLine()) != null)
                {
                    if (int.TryParse(line, out batchItem))
                    {
                        readItems.Add(batchItem);
                    }
                }
            }

            CurrrentFile = FileName;
            FileInfo f = new FileInfo(FileName);
            lock (LockObject)
            {
                TextWriter = f.AppendText();
                TextWriter.AutoFlush = true;
            }

            if (readItems.Count > 0)
                FileOpened(readItems);


        }

我正在尝试检测可能的问题,例如/文件名为空。

在捕获和记录异常的类中,我显然有一个catch(ArgumentNullException ex)

我是否也应该捕获StreamReader 构造函数和FileInfo 构造函数可能引发的异常?

我知道这听起来很傻,但我想知道我是否应该对我抛出的异常有明确的捕获,然后是一般的异常捕获,无论它是 catch(Exception ex) 还是围绕上述代码尝试捕获并重新抛出自定义例外。否则我的 try/catch 块有大约 12 个单独的 catch 语句!

【问题讨论】:

  • 必填link Eric Lippert 关于不同类型异常以及处理它们的正确方法的文章。
  • @FrédéricHamidi 但是在 StreamReader/FileInfo 的场景中,我无能为力。如果我检查自己的文件名是否无效,我会自己抛出异常并捕获它,所以我不会真正阻止任何事情

标签: c# .net exception design-patterns try-catch


【解决方案1】:

使用尝试捕获 如果有错误,您可以在 catch 部分中捕获它。先使用特定异常,后使用通用异常。

【讨论】:

    【解决方案2】:

    始终确保将您的一般异常(即 SystemException/ApplicationException/Exception catch 子句)放在最后。所以准备明显。在您的情况下,SecurityException、FileNotFound、PathNotFound 等异常。请查看 MSDN 文档以了解这些 API 以及它们抛出的各种异常。

    创建一个通用异常的问题是你永远不会知道问题到底是什么,甚至 FxCop 也会为此发出警告。如果你的 catch 子句更多,没问题,但只要确保你拆分并捕获异常。例如,如果我们在不同的场合打开 2 个文件,那么分别捕获它们而不是一个。

    【讨论】:

      【解决方案3】:

      我是否也应该捕获由 StreamReader 构造函数和 FileInfo 构造函数?

      简而言之:知道抛出了这些异常,你能做一些合理的事情吗?如果是,抓住他们并去做。如果没有,让它打破。

      【讨论】:

        【解决方案4】:

        一般来说,如果您遵循一些简单的规则,您可以大大简化您的异常处理代码。

        1.只捕获和处理您实际上可以做一些事情的异常

        如果您实际上无法从异常中恢复,那么您根本不应该捕获它。让异常冒泡到可能的最高点(通常是用户界面)。

        当您确实捕获异常时,您应该捕获非常具体的异常,并尽可能避免通用异常处理。

        try
        {
           DoSomeStuff();
        }
        catch(HolyCrapItBlewedUpException ex)
        {
           RecoverFromExplosion();
        }
        catch(Exception ex)
        {
           //I really have no idea what happened, and I can't do
           // anything about it, but I'm going to catch the
           // exception anyway cause it makes me feel better
        }
        

        上述规则有咳嗽例外,但这将我们引向第二条规则。

        2。仅对日志记录和实现隐藏使用通用异常处理

        既然你应该让你的异常一直冒泡到最高层,任何让它到达顶层的东西都是一个错误。此时,您应该记录该异常并向用户显示一些友好的消息。

        try
        {
           DoSomeStuff();
        }
        catch(Exception ex)
        {
           //At this point it's a bug... we need to squash it!
           LogException(ex);
           ShowUserRecoveryOptions();
        }
        

        您可能希望这样做的另一个地方是为了维护 API 合同并隐藏实现细节。如果最终用户正在调用一个方法,他们可能不需要知道所有可能发生的问题,只需知道它没有工作即可。

        public void MakeMeASandwich()
        {
           try
           {
              MakeCallerASandwich();
           }
           catch(SecurityException ex)
           {
              //It's still best to distinguish between certain exceptions
              // as long as it makes sense to the caller.
              throw new NoIWillNotMakeYouASandwichException(ex);
           }
           catch(Exception ex)
           {
              throw new SorryICantMakeYouASandwichException(ex);
           }
        }
        

        3.避免像瘟疫这样的例外!

        例外应该是,嗯...例外!在大多数情况下,您应该能够通过简单地提前对其进行编码来避免异常。真正的异常应该代表您无法预测会发生的事情。一个简单的例子是检查文件是否存在。

        try
        {
           File.Open("blah.txt");
        }
        catch(FileNotFoundException ex)
        {
           File.Create("blah.txt");
        }
        

        在那个例子中,我知道文件可能不存在......所以我应该编写代码来确保这种情况几乎永远不会发生。

        var fileName = "blah.txt";
        
        if(!File.Exists(fileName))
           File.Create(fileName);
        
        File.Open(fileName);
        

        现在,FileNotFoundException 仍然可以在这里抛出,但我们将如何处理呢?很明显,这段代码不能再做任何事情了,因为确实发生了EXCEPTIONAL。我们可以让异常冒泡到下一层,因为我们在这里无能为力。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-12-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-29
          • 2018-03-25
          • 1970-01-01
          相关资源
          最近更新 更多