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– James2018年08月07日 08:11:18 +00:00Commented Aug 7, 2018 at 8:11
-
yes, The question goes to the heart of whether exceptions are part of the class deinfition ala javaEwan– Ewan2018年08月07日 08:29:33 +00:00Commented Aug 7, 2018 at 8:29
4 Answers 4
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.
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– James2018年08月07日 08:14:03 +00:00Commented Aug 7, 2018 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 ofthrow new CustomException()
you dothrow 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– Flater2018年08月07日 08:43:28 +00:00Commented Aug 7, 2018 at 8:43
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– James2018年08月07日 08:59:13 +00:00Commented Aug 7, 2018 at 8:59
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>