150

我目前正在编写一个小型框架,公司内部其他开发人员将在内部使用该框架。

我想提供良好的 Intellisense 信息,但我不确定如何记录抛出的异常。

在以下示例中:

public void MyMethod1()
{
    MyMethod2();

    // also may throw InvalidOperationException
}

public void MyMethod2()
{
    System.IO.File.Open(somepath...); // this may throw FileNotFoundException

    // also may throw DivideByZeroException
}

我知道记录异常的标记是:

/// <exception cref="SomeException">when things go wrong.</exception>

我不明白的是如何记录由调用的 MyMethod1()代码引发的异常?

  • 我应该记录抛出的异常吗MyMethod2()
  • 我应该记录抛出的异常File.Open()吗?

记录可能的例外情况的最佳方式是什么?

4

8 回答 8

115

您应该记录您的代码可能引发的每个异常,包括您可能调用的任何方法中的异常。

如果列表有点大,您可能想要创建自己的异常类型。捕获您在方法中可能遇到的所有问题,将它们包装在您的异常中,然后抛出它。

另一个你可能想要这样做的地方是,如果你的方法是在你的 API 上。就像外观将多个接口简化为单个接口一样,您的 API 应该将多个异常简化为单个异常。使调用者更容易使用您的代码。


为了回答 Andrew 的一些担忧(来自评论),有三种类型的例外:您不知道的例外、您知道但无能为力的例外,以及您知道但可以做某事的例外。

那些你不知道的你想放手。它的原则是快速失败 - 最好让您的应用程序崩溃而不是进入可能最终破坏数据的状态。崩溃会告诉你发生了什么以及为什么,这可能有助于将该异常从“你不知道的”列表中移出。

您知道但无能为力的是 OutOfMemoryExceptions 之类的异常。在极端情况下,您可能希望处理这样的异常,但除非您有一些非常显着的要求,否则您将它们视为第一类——让他们去吧。您是否必须记录这些例外情况?在新建对象的每个方法上记录 OOM 看起来很愚蠢。

你知道并且可以做一些事情的是你应该记录和包装的那些。

您可以在此处找到有关异常处理的更多指南。

于 2009-01-20T13:51:29.567 回答
106

您应该使用标准的 xml 文档

/// <exception cref="InvalidOperationException">Why it's thrown.</exception>
/// <exception cref="FileNotFoundException">Why it's thrown.</exception>
/// <exception cref="DivideByZeroException">Why it's thrown.</exception>
public void MyMethod1()
{
    MyMethod2();
    // ... other stuff here
}

/// <exception cref="FileNotFoundException">Why it's thrown.</exception>
/// <exception cref="DivideByZeroException">Why it's thrown.</exception>
public void MyMethod2()
{
    System.IO.File.Open(somepath...);
}

/// <exception cref="FileNotFoundException">Why it's thrown.</exception>
public void MyMethod3()
{
    try
    {
        MyMethod2();
    }
    catch (DivideByZeroException ex)
    {
        Trace.Warning("We tried to divide by zero, but we can continue.");
    }
}

这样做的价值在于您提供了可能发生的已知异常的文档。如果您使用的是 Visual Studio,则此文档在智能感知中可用,并且可以稍后提醒您(或其他人)您可以预期的异常。

您要指定具体的异常类型,因为您可能能够处理一种类型的异常,而其他类型是严重问题的结果,无法纠正。

于 2009-01-20T13:46:28.263 回答
36

您可以通过使用几个很棒的插件来简化您的文档过程。其中之一是GhostDoc,它是 Visual Studio 的免费插件,可生成 XML-doc 注释。此外,如果您使用ReSharper,请查看适用于 ReSharper 的出色Agent Johnson 插件,它添加了一个选项来为抛出的异常生成 XML 注释。

更新:似乎 Agen Johnson 不适用于 R# 8,请查看Exceptional for ReSharper作为替代方案......

第 1 步:GhostDoc 生成 XML 注释 (Ctrl-Shift-D),而 ReSharper 的 Agent Johnson 插件也建议记录异常:

第1步

第 2 步:使用 ReSharper 的快捷键 (Alt-Enter) 来添加异常文档:

第 2 步 http://i41.tinypic.com/osdhm

希望有帮助:)

于 2009-01-20T14:28:11.550 回答
12

据我了解,使用 <exception> 元素的目的是在装饰方法时使用它,而不是异常:

/// <summary>Does something!</summary>
/// <exception cref="DidNothingException">Thrown if nothing is actually done.</exception>
public void DoSomething()
{
// There be logic here
}

应该在这些方法中捕获、处理和记录可以被其他调用方法抛出的异常。应该记录可能由 .NET 引发的异常,或由您自己的代码显式引发的异常。

至于比这更具体,也许您可​​以捕获并抛出您自己的自定义异常?

于 2009-01-20T13:44:49.500 回答
4

您的方法的部分合同应该是检查先决条件是否有效,因此:

public void MyMethod2()
{
    System.IO.File.Open(somepath...); // this may throw FileNotFoundException
}

变成

/// <exception cref="FileNotFoundException">Thrown when somepath isn't a real file.</exception>
public void MyMethod2()
{
    FileInfo fi = new FileInfo( somepath );
    if( !fi.Exists )
    {
        throw new FileNotFoundException("somepath doesn't exists")
    }
    // Maybe go on to check you have permissions to read from it.

    System.IO.File.Open(somepath...); // this may still throw FileNotFoundException though
}

使用这种方法,可以更轻松地记录您显式抛出的所有异常,而不必同时记录OutOfMemoryException 可能抛出的 a 等。

于 2009-01-20T14:10:29.323 回答
1

您应该记录您的方法可能引发的所有异常。

为了隐藏实现细节,我会尝试自己处理 MyMethod2 的一些异常。

如果您无法处理或解决异常,您可以考虑追溯它们。主要打包/包装在调用者更有意义的异常中。

于 2009-01-20T13:43:51.390 回答
1

事实上,正如已经回答的那样,记录异常的方法是使用 XML 注释。

除了插件之外,您还可以使用可与 TFS 集成的静态分析工具,以确保记录异常。

在下面的链接中,您可以看到如何为 StyleCop 构建自定义规则,以验证您的方法引发的异常是否被记录在案。

http://www.josefcobonnin.com/post/2009/01/11/Xml-Documentation-Comments-Exceptions-I.aspx http://www.josefcobonnin.com/post/2009/01/15/Xml-Documentation -Comments-Exceptions-II.aspx

问候。

于 2009-04-29T09:29:44.317 回答
0

在您的方法中记录预期的异常,在您的示例中,我会让用户知道该方法可以抛出未找到文件的异常。

请记住,这是为了通知调用者会发生什么,以便他们可以选择如何处理它。

于 2009-01-20T13:44:18.050 回答