【问题标题】:How to figure out which exceptions a certain method can throw if that is not documented in MSDN?如果 MSDN 中没有记录,如何确定某个方法可以抛出哪些异常?
【发布时间】:2014-01-16 19:22:32
【问题描述】:

最近我遇到了一个我没有预料到的异常,因为 MSDN 中没有记录它可以由特定的构造函数抛出。所以这里是抛出异常的 C# 行:

    using (StreamReader sr = new StreamReader(filePath))

filePath 这里是应该包含某个文件的完整路径的字符串。问题是我的“filePath”变量实际上是文件夹的路径,而不是文件的路径。因此,构造函数 StreamReader(filePath) 抛出:

System.UnauthorizedAccessException: Access to the path 'D:\testFolder' is denied.

好的,所以这显然是一个错误,我已经通过传递正确的路径来修复它......但是查看 StreamReader(string) 的 MSDN 文档我没有看到任何提及此异常的内容。在异常部分有:

  • ArgumentException - 路径是一个空字符串 ("")。
  • ArgumentNullException - 路径为空。
  • FileNotFoundException - 找不到文件。
  • DirectoryNotFoundException - 指定的路径无效,例如位于未映射的驱动器上。
  • IOException - 路径包含文件名、目录的错误或无效语法 名称或卷标。

再想一想这个问题,我猜抛出的异常实际上应该是 IOException 而不是 UnauthorizedAccessException。这是 .NET Framework 中的错误吗?问题是我有 IOException 处理程序通知用户无效的文件路径并继续应用程序工作流程而不会崩溃。这个 UnauthorizedAccessException 使我的应用程序崩溃,因为它没有得到处理。

我应该如何处理这类问题?我想我过去遇到过类似的未记录异常的问题,但这确实促使我研究这个问题并在这里提出问题。

【问题讨论】:

    标签: c# .net exception exception-handling msdn


    【解决方案1】:

    不幸的是,真的没有办法以一般的方式处理这个问题。 C# 和 CLR 的性质使得很难(如果不是完全不可能的话)确定可以从方法中抛出的完整异常集。有一些简单的 API 是可能的,但一般来说不是。

    我处理这个问题的方法是简单地捕获Exception。 CLR 的最新版本默认情况下无法捕获 dangerous 异常。因此,您只会捕获 safer 异常。除非您想对一个非常具体的错误做出反应,否则只需抓住所有错误并针对 API 调用失败采取适当的措施

    【讨论】:

      【解决方案2】:

      虽然您事先不能 100% 了解方法可以抛出哪些类型的异常,但有一些方法可以避免陷入这个问题,这确实是 CLR 中缺少的东西,您遵循一个通用模式,即捕获来自Exception 的所有异常,然后进一步区分哪些可以处理,哪些不能处理,

      try
      {
      }
      catch (FileNotFoundException)
      {
      }
      catch (DirectoryNotFoundException)
      {
      }
      catch (IOException)
      {
      }
      catch (Exception exception)
      {
          // For the ones you do not know how to handle, at least document it and throw
          log(exception);
          throw;
      }
      

      这将使您的调试更加容易。

      请注意,这种模式将基于层次结构,派生的异常类型应该首先执行,否则您将面临先执行派生较少的 catch 的风险。换句话说,不要这样做,

      try
      {
      }
      catch (IOException)
      {
           // Will get executed for both DirectoryNotFoundException and
           // FileNotFoundException even though you specified specific ways to 
           // handle these types
      }
      catch (DirectoryNotFoundException)
      {
      }
      catch (FileNotFoundException)
      {
      }
      

      或者,您可以只捕获 Exception 并使用 if 来测试实际类型,这不是那么漂亮,但可能更灵活,

      try
      {
      }
      catch (Exception exception)
      {
           if (exception.GetType() == typeof(IOException))
           {
           }
           else if (exception.GetType() == typeof(DirectoryNotFoundException))
           {
           }
           else if (exception.GetType() == typeof(FileNotFoundException))
           {
           }
           else
           {
               log(exception);
               throw;
           }
      }
      

      【讨论】:

        【解决方案3】:

        我认为无论如何都看不到方法可能引发的所有可能异常。事实是,您必须递归所有方法调用才能获得该列表,而这不会发生。

        就我个人而言,我对异常处理的感觉更像是 Joel Spolsky (http://www.joelonsoftware.com/items/2003/10/13.html);我很少捕获特定的异常,并且尽可能地避免使用 try-catch。在这种情况下,我会使用catch (Exception e) 来避免这个问题,然后我会使用 if-else 来尽可能适当地处理不同的类型。

        【讨论】:

          【解决方案4】:

          我以前读过这篇文章……希望它能给你一些见解。微软项目经理在blog 中写了这个。

          【讨论】:

            【解决方案5】:

            在多种情况下,Microsoft 会针对某些方法给出不正确的异常或 msdn 中未提及的异常。我也遇到过类似的情况,我必须捕获一般异常来代替特定异常(在我的例子中是 system.formatexception)。

            但是您可能会面临诸如避免静态 FxCop 违规之类的问题。根据 fxcop 的说法,不应捕获一般异常。

            我们找到了错误异常类型的原因,并且是另一个异常中的异常导致真正的异常回避。

            **获得异常就像身体疼痛。两者都表明系统存在问题,但为所有疼痛服用相同的药物并不好,因此请尝试在这种情况下捕获特定的异常。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2010-11-02
              • 2011-11-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-11-22
              • 1970-01-01
              • 2014-01-15
              相关资源
              最近更新 更多