如何指定接口的实现者抛出的异常?

时间:2010-10-13 11:43:26

标签: c# exception interface dependency-injection strategy-pattern

我目前正在开发一个解决方案,并以一种强大的方式实现策略/提供者模式。因此,该解决方案公开了许多接口,并包含这些接口的默认实现,可以通过DI类型方法替换。

如果主机应用程序使用了许多这些接口,它希望处理可能发生的某些异常,例如IDataRetriever接口有一个方法SomeDataType GetData(int timeout);,并且主机可以处理一些自定义异常,例如DataRetrievalTimeoutExceptionNetworkConnectionException

我的问题是,标记接口类的最佳方法是什么,当开发人员实现它时,他们会知道应该抛出某些异常并由主机处理?

目前我刚刚将xml标签添加到方法xml注释中 - 这是否足够?

6 个答案:

答案 0 :(得分:12)

XML标签(以及您想要编写的任何其他文档)基本上是您目前在“vanilla”.NET中最接近的。

您可能希望查看Code Contracts,它允许您使用合同注释您的界面,其中包括例外,先决条件等。

答案 1 :(得分:2)

你不能在界面中。你可以在基类。

public interface IFoo
{    
  /// <summary>
  /// Lol
  /// </summary>
  /// <exception cref="FubarException">Thrown when <paramref name="lol"> 
  /// is <c>null</c></exception>
  /// <remarks>Implementors, pretty please throw FE on lol 
  /// being null kthx</remarks>
  void Bar(object lol);
}

VS

public abstract BaseFoo
{    
  /// <summary>
  /// Lol
  /// </summary>
  /// <exception cref="FubarException">Thrown when <paramref name="lol"> 
  /// is <c>null</c></exception>
  public void Bar(object lol)
  {
    if(lol == null)
      throw new FubarException();
    InnerBar(lol);
  }

  /// <summary>
  /// Handles execution of <see cref="Bar" />.
  /// </summary>
  /// <remarks><paramref name="lol"> is guaranteed non-<c>null</c>.</remarks>
  protected abstract void InnerBar(object lol);
}

答案 2 :(得分:2)

我建议在接口中定义异常类,并指定除非CPU处于激烈状态或其他如此剧烈的情况下,否则不应允许任何不从这些异常派生的异常转义(即便如此,它可能不是有一个明确定义的IWoozle.SystemCorruptionException的坏主意,以便如果一个Pokemon处理程序只是捕获,记录并抛出异常,日志将反映出至少有人认为异常是重要的。)

我认为微软的建议是避免定义自定义异常类型是不幸的,因为这意味着没有干净的方法可以区分IEnumerator<T>.MoveNext()是否抛出InvalidOperationException,因为在枚举期间底层集合已被更改,或者IEnumerator<T>.MoveNext()的内部处理是否遇到InvalidOperationException并简单地让它冒泡到调用者。如果相反,IEnumerator<T>.MoveNext()在前一种情况下投了IEnumerator.InvalidatedEnumeratorException,则转义的任何InvalidOperationException都必须代表后一种情况。

答案 3 :(得分:1)

这不应该由任何类实现接口吗?

例如,如果我使用您的接口并使用GetData方法实现我自己的类,我可以从任何地方“获取”数据。假设它是一个Web服务,那么可以抛出的异常类型可能与我从本地文件系统“获取”数据时的异常类型不同。

因此,在我的实现中,我将实现(并记录)特定于implmentation的那些异常,以便使用该实现的任何代码都可以处理它们。处理这些异常的方式可能非常具体,例如我在网络应用程序中使用它们而不是桌面应用程序。

答案 4 :(得分:0)

我认为提供此信息的最佳方式是在为每个界面提供的XML文档中。在那里,您可以指定方法抛出的异常,以便主机可以处理该错误。

答案 5 :(得分:0)

如果您不能支持通用基类,另一种策略是扩展方法实现。

public static void ThisMethodShouldThrow(this Iinterface obj)
{
     if(obj.ConditionToThrowIsMet) throw new...
}

这样可以让您不需要继承链。