Is it ok for different implementing classes to throw different exception types?
If i have an interface, which i add comments to to identify that a specific exception will be thrown, is it ok for implementing classes to throw different exceptions?
A (bad) example is:
public interface IWidgetWorker {
/// <summary>
/// Do the work required for the specified work id.
/// </summary>
/// <param name="workId">The id of the piece of work to do</param>
/// <exception cref="ArgumentException">Thrown if workId is empty</exception>
public void DoWork(Guid workId);
}
public class DatabaseWidgetWorker : IWidgetWorker {
public void DoWork(Guid workId) {
// throw some database related exception
}
}
public class WebWidgetWorker : IWidgetWorker {
public void DoWork(Guid workId) {
// throw some web related exception
}
}
Maybe i add a WidgetWorkerException
class? Where do i document what the specific exceptions that the implementing clas开发者_如何学运维ses might throw?
Part of an interface design often documents the expected exceptions. These exceptions are logical at the time of the creation of the interface, for example an InvalidOperationException
for when a method is called and the object is in the wrong state or an ArgumentOutOfRangeException
when an improper parameter is passed.
However, interfaces can be implemented in any number of ways. It's entirely possible for an implementation to look at a file system or call to a database, introducing a range of exceptions that were not foreseeable when the interface was defined.
The only reason you would want to know that a method throws a specific exception is to be able to handle that condition differently from general exception handling. When you make a call through an interface, you are coding against the interface and not the implementation. You cannot know how the implementation works and therefore cannot handle exceptions in any specific manner. You must fall back to more general exception handling.
The rule of thumb should be to document exceptions which are sensible given the exposed interface, but that you should expect an implementation to throw exceptions beyond these. Robust code will have a mechanism for handling these unknown exceptions in a generic fashion.
Implementing classes should only throw the exceptions specified in the interface. If the interface doesn't provide for any possibility to report the error, either the interface is badly designed or the implementors should suck it up, because the interface user really doesn't care.
This is probably subjective. My feeling is that the implementing classes should throw whatever exceptions that is natural to throw at the time. The interface does not declare which exceptions are allowed and which aren't. The compiler does not look at your comments, and a class can throw other exceptions and still be a valid implementation of your interface.
If, for some reason you need those exceptions to be of a single type, you could catch them and rethrow them with the original as inner exception wherever IWidgetWorker.DoWork is called.
The situation where workId is empty, could be handled before the call goes to the implementation, so there is no reason why different implementations should handle the same checking and throwing of ArgumentException.
It might be different in other programming environments. I think that possible exceptions must be declared in some languages, but not here.
The documentation of your interface could say something about how various exceptions are interpreted and what the consuming code will do. Maybe the consuming code will try again after some time interval if the exception is such and such, but will terminate report error in other cases.
精彩评论