记录接口的抛出异常是否是一种好的做法



正如标题所说:记录接口抛出的异常是一种好的做法吗?是否存在公认的最佳实践?我觉得这是一个不应该以任何方式包含在界面中的实现细节,但同时我觉得它是界面用户应该拥有的有价值的信息。

这样的注释是否是一种好的做法是另一个讨论的主题,所以为了限制这个问题的范围,让我们假设我们已经同意用这样的注释来记录代码是一种很好的做法。这里的"像这样的评论"指的是你可以从中生成东西的评论,即文档或元数据,而不仅仅是"普通"评论。示例包括XML文档、Javadoc和Doxygen。

现在,如果可以达成一致的最佳实践,那么这些C#示例中的哪一个是更好的实践?

接口无例外文件:

public interface IMyInterface {
    /// <summary>
    /// Does something.
    /// </summary>
    void DoSomething();
}

与异常文档的接口:

public interface IMyInterface {
    /// <summary>
    /// Does something.
    /// </summary>
    /// <exception cref="System.Exception">Something went wrong.</exception>
    void DoSomething();
}

接口是契约,如果该契约的一部分包含引发异常的情况,那么您肯定应该将其包含在文档中。您可以看到在.NET框架的所有接口中记录的异常示例,例如IEnumerator有很多异常。(通过右键单击IEnumerator声明并导航到"元数据视图"检索到的文本(

  public interface IEnumerator
  {
    /// <summary>
    /// Advances the enumerator to the next element of the collection.
    /// </summary>
    /// 
    /// <returns>
    /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
    /// </returns>
    /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
    bool MoveNext();
    /// <summary>
    /// Sets the enumerator to its initial position, which is before the first element in the collection.
    /// </summary>
    /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
    void Reset();
    /// <summary>
    /// Gets the current element in the collection.
    /// </summary>
    /// 
    /// <returns>
    /// The current element in the collection.
    /// </returns>
    /// <filterpriority>2</filterpriority>
    object Current { get; }
  }

接口只定义要执行的操作的契约,而不定义它们是如何实现的。考虑以下示例:

void Sort(SortOrder order);

您可能会想添加一个throws ArgumentNullException if order is null注释,但如果接口的实现者决定在SortOrder上接收null意味着它应该使用默认的SortOrder,会发生什么?(错误的决定,但有可能(。对于实现接口的人来说,这应该是一个有效的决定,如果不能选择这样的决定,那么你应该提供一个抛出异常的抽象基类,而不是接口。

向接口添加异常就像使接口从IDisposable接口继承一样。这些都是不应该滑入接口定义的实现细节。

最新更新