如何确定某个方法可能抛出哪些异常,如果在MSDN中没有记录?

8

最近我遇到了一个异常,我之前并没有预料到,因为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 - 路径为null。
  • FileNotFoundException - 找不到文件。
  • DirectoryNotFoundException - 指定的路径无效,例如在未映射的驱动器上。
  • IOException - 路径包括文件名、目录名或卷标的不正确或无效语法。

再思考一下这个问题,我想抛出的异常实际上应该是IOException而不是UnauthorizedAccessException。这是.NET Framework的一个错误吗?问题是我已经有了IOException处理程序,可以通知用户有关无效文件路径并继续应用程序工作流程而不会崩溃。这个UnauthorizedAccessException因为未被处理而导致了我的应用程序崩溃。

我该如何处理这种问题?我认为我遇到过类似的未记录异常的问题,但这个问题真的激励我去研究这个问题并在这里提问。

5个回答

7

很遗憾,在一般情况下,我们无法解决这个问题。C#和CLR的本质使得很难(甚至不可能)确定从一个方法中能够抛出的所有异常。虽然有些简单的API可以做到,但通常不行。

我的处理方式是简单地捕获Exception。最近的CLR版本默认禁止捕获危险的异常,因此您只会捕获到较为安全的异常。除非您想针对特定的错误做出反应,否则请捕获全部异常并采取适当的措施来处理API调用失败。


3

虽然你不能事先百分之百地了解一个方法会抛出哪些类型的异常,但有方法可以避免陷入这个问题,这确实是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;
     }
}

2
我认为没有办法查看方法可能抛出的所有异常。事实是,您必须递归遍历所有方法调用才能获得该列表,这是不可能发生的。
就我个人而言,我对异常处理的感觉更接近Joel Spolsky的观点(http://www.joelonsoftware.com/items/2003/10/13.html);我很少捕获特定的异常,并尽可能地避免使用try-catch。在这种情况下,我将使用catch (Exception e)来避免这个问题,然后我将使用if-else来尽可能适当地处理不同类型的异常。

1

我之前阅读过这篇文章……也许它能给你一些启示。微软项目经理在博客中写道。


1
在某些情况下,Microsoft会给出不正确的异常或未在MSDN中提到某些方法的异常。我也遇到过类似的情况,在特定异常(在我的情况下是system.formatexception)的位置上捕获常规异常。
但是,这样做可能会导致问题,例如避免静态FxCop违规。根据FxCop,不应该捕获常规异常。
我们发现获取错误异常类型的原因是另一个异常内部的异常导致真正的异常逃避。
获取异常就像在身体上感受到疼痛一样。两者都表明系统存在问题,但是对所有疼痛使用同一种药物并不好,因此在这种情况下尝试捕获特定异常。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接