4

I have an interface IMyService in a class library.

I have an implementation of this interface MyService in a separate class library.

MyService may raise a custom exception CustomException.

Should CustomException live in the interface class library, or the implementation class library?

  • My own thoughts on this are that the exception should probably live with the implementation, as the exception is most likely an implementation detail. The drawback to that is that you cannot act on specific exceptions within the interface's class library (which in my case is also my "business logic" library). – James Aug 7 '18 at 8:11
  • yes, The question goes to the heart of whether exceptions are part of the class deinfition ala java – Ewan Aug 7 '18 at 8:29
6

This depends on the meaning/context of the exception.

For example, the current project I'm working on uses a BusinessException class. This is used for any explicitly thrown exception with a message (in more layers than just the BLL - I'm aware that the name is misleading). The BusinessException therefore lives in the domain layer (= where IMyService is located).

For those interested, the main reason to use BusinessException is that we allow these exception messages to be returned to the consumer of our web API, whereas all other exceptions get rephrased to "an error has occurred".

One of our business logic classes has a particular UserIsInactiveException. This particular exception is only used as a particular business logic rule (inactive users are not allowed to update data). Therefore, we inherently know that it will only be used on the Business Logic Layer, and therefore it lives in the BLL project (= where MyService is located).

UserIsInactiveException inherits from BusinessException. But the location of the exceptions would be the same regardless of them having an inheritance or not.

My own thoughts on this are that the exception should probably live with the implementation, as the exception is most likely an implementation detail.

What you say isn't incorrect, but it's not universally applicable either. Some exceptions are part of your framework more than they are an implementation detail, for example when your framework is expected to handle certain (custom) exceptions differently.

3

Should CustomException live in the interface class library, or the implementation class library?

Do you anticipate that all implementations of IMyService should support throwing CustomException, or just MyService?

If the former, put it in the interface library, so it's accessible to all implementations.

If the latter, then there's a further decision to be made. Does the rest of the app, save for any code associated with dependency injection, deal solely with IMyService? If so, again you should put it into the interface library, otherwise those other parts of the code must reference the implementation library just to get a reference to the exception.

If the answer is no though, or that implementation library must be referenced for other reasons, put it in the implementation library, so that it's collocated with the class that throws it.

  • "Do you anticipate that all implementations of IMyService should support throwing CustomException, or just MyService". Apart from unit testing implementations, yes all implementations will throw the exceptions (there is, as usual, only one implementation). However, C# has no mechanism for enforcing the exceptions that an interface method can throw, which makes it feel like a moot point. – James Aug 7 '18 at 8:14
  • @James However, C# has no mechanism for enforcing the exceptions that an interface method can throw, You can implement this indirectly, if you only allow the exception to be created via a method (since you can enforce a method signature via interfaces). So instead of throw new CustomException() you do throw CreateException(). The syntax remains otherwise unchanged (constructor arguments become method parameters) and you can now enforce an exception type. As a quick and dirty example: interface IThrows<TException> where TException : Exception { TException CreateException(); } – Flater Aug 7 '18 at 8:43
2

I'm going to go with "Keep custom exceptions with the implementation rather than the Interface"

By putting the Custom Exceptions in the Interface library you are implying that they are part of the contract that the interface enforces. If C# supported it, you would go further and specify throws on each method like Java.

However, I believe this approach is flawed. It implies that the Custom Exception will be known about by calling code and the only reason for that would be to use them for flow control. A recognised BAD THING(tm)

Furthermore we can easily imagine examples where each implementation would want to expose their own Custom Exceptions.

Consider a IRepository, with implementations Repository_Database and Repository_Files. Both implementations would by their nature want to throw exceptions related to their underlying implementations, "Can't connect to database", "Can't open file" etc

Rather than trying to force these repositories to catch and throw a generic "Cant initiate" exception, which the calling code would then use for flow control, I would add an Open method/ IsOpen property to the repository interface, should this be something that implementations be required to expose.

  • That's a good point about flow control. – James Aug 7 '18 at 8:59
0

Should CustomException live in the interface class library, or the implementation class library?

Yes of course! If this occurs because it is a common behavior of your process, you must include the exception statement as a comment at the top of the method code. I recommend you include it in the interface. The documentation for your method will look like this:

///<sumary>
/// Method's description
///</sumary>
///<exception cref="CustomException">Occurs when an incident happens</exception>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.