简体   繁体   English

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

[英]How to specify exceptions to be thrown by an implementor of an interface?

I'm currently developing a solution and have designed it in a way such that it strongly implements the strategy/provider pattern. 我目前正在开发一个解决方案,并以一种强有力地实现策略/提供者模式的方式进行设计。 As such the solution exposes a number of interfaces and contains default implementations of these interfaces which can be replaced via a DI type methodology. 因此,该解决方案公开了许多接口并包含这些接口的默认实现,这些接口可以通过DI类型方法替换。

Where the host application uses a number of these interfaces it is expecting to handle certain exceptions that may occur, for example IDataRetriever interface has a method SomeDataType GetData(int timeout); 在主机应用程序使用多个这些接口的情况下,它期望处理可能发生的某些异常,例如IDataRetriever接口具有方法SomeDataType GetData(int timeout); and the host can handle some custom exceptions such as DataRetrievalTimeoutException or NetworkConnectionException . 并且主机可以处理一些自定义异常,例如DataRetrievalTimeoutExceptionNetworkConnectionException

My question is, what is the best way to mark up the interface class such that when a developer implements it they would know that certain exceptions should be thrown and would be handled by the host? 我的问题是,标记接口类的最佳方法是什么,当开发人员实现它时,他们会知道应该抛出某些异常并由主机处理?

At the moment I have just added the exception xml tags to the methods xml comment - does this suffice? 目前我刚刚将xml标签添加到方法xml注释中 - 这是否足够?

The XML tags (and any other documentation you want to write) are basically the closest you've got in "vanilla" .NET at the moment. XML标签(以及您想要编写的任何其他文档)基本上是您目前在“vanilla”.NET中最接近的。

You might want to look at Code Contracts which lets you annotate your interface with contracts, which can include exceptions, preconditions etc. 您可能希望查看代码约定 ,它允许您使用合同注释您的接口,其中包括异常,前置条件等。

You cannot in an interface. 你不能在一个界面。 You CAN in a base class. 你可以在基类。

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);
}

I would suggest defining exception classes within the interface, and specifying that no exceptions which do not derive from those should be allowed to escape unless the CPU is on fire or other such drastic situation exists (even then, it might not be a bad idea to have an explicitly-defined IWoozle.SystemCorruptionException so that if a Pokemon handler simply catches, logs, and throws out the exception, the log will reflect that at least someone thought the exception was important). 我建议在接口中定义异常类,并指定除非CPU处于激烈状态或存在其他如此剧烈的情况,否则不应允许任何不从那些派生的异常转义(尽管如此,它可能不是一个坏主意有一个显式定义的IWoozle.SystemCorruptionException这样如果一个Pokemon处理程序只是捕获,记录并抛出异常,日志将反映出至少有人认为异常是重要的)。

I consider Microsoft's recommendation to avoid defining custom exception types to be unfortunate, since it means that there's no clean way to distinguish whether IEnumerator<T>.MoveNext() throws an InvalidOperationException because the underlying collection was altered during enumeration, or whether the internal processing of IEnumerator<T>.MoveNext() encounters an InvalidOperationException and simply lets it bubble up to the caller. 我认为Microsoft的建议是避免定义自定义异常类型是不幸的,因为这意味着没有干净的方法来区分IEnumerator<T>.MoveNext()抛出InvalidOperationException因为枚举期间底层集合被更改,或者是否内部处理IEnumerator<T>.MoveNext()遇到InvalidOperationException ,只是让它冒泡到调用者。 If instead, IEnumerator<T>.MoveNext() threw an IEnumerator.InvalidatedEnumeratorException in the former case, then any InvalidOperationException which escaped would have to represent the latter case. 相反, IEnumerator<T>.MoveNext()在前一种情况下抛出了IEnumerator.InvalidatedEnumeratorException ,然后任何转义的InvalidOperationException都必须代表后一种情况。

Should this not be up to whatever class implements the Interface? 这不应该由任何类实现接口吗?

Eg if I take your Interface and implement my own class, with a method GetData, I could be 'getting' data from anywhere. 例如,如果我使用您的接口并使用GetData方法实现我自己的类,我可以从任何地方“获取”数据。 Lets say it was a web service then the types of exceptions that could be thrown could be different to those if I was 'getting' data from local file system. 假设它是一个Web服务,那么可以抛出的异常类型可能与我从本地文件系统“获取”数据时的异常类型不同。

So in my implementation I would implement (and document) those exceptions specific to the implmentation so that whatever code is using the implementation could handle them. 因此,在我的实现中,我将实现(并记录)特定于implmentation的那些异常,以便使用该实现的任何代码都可以处理它们。 How those exception are handled may be very specific to the implementation, say I am consuming them in a web app as opposed to a desktop app. 如何处理这些异常可能对实现非常具体,比如我在Web应用程序中使用它们而不是桌面应用程序。

I think the best way to provide this information is in the XML documentation that you would provide for each interface. 我认为提供此信息的最佳方法是在为每个接口提供的XML文档中。 There you can specify what Exception is thrown by the method so that the host can handle that error. 在那里,您可以指定方法抛出的异常,以便主机可以处理该错误。

Another strategy if you can't support a generic base class, is extension method implementations. 如果您不能支持通用基类,另一种策略是扩展方法实现。

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

This has the benefit of allowing you to not require an inheritance chain. 这样做的好处是不需要继承链。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM