Home > other >  Exception naming conventions and scope
Exception naming conventions and scope

Time:05-10

We have multiple .NET 6 projects with Nullable Reference Types enabled. So far, we've been too lazy to assign or create exception types for specific errors.

The most commonly used Exception types currently in our code are ArgumentException and ArgumentNullException.

The use cases for the latter are mostly:
In full properties: (I think these are fine)

public string OfferId 
{ 
    get => _offerId ?? throw new ArgumentNullException($"{nameof(ItemDTO)}.{nameof(OfferId)}");
    set => _offerId = value;
}

In constructors: (these are also debatably fine)

NativeProductId = rawProduct.NativeProductId ??
            throw new ArgumentNullException($"{nameof(rawProduct)}.{nameof(rawProduct.NativeProductId)}");

And then we use them for anything that remotely smells of null, using them if an HttpRequest returns empty content, if JsonConvert returns null, etc. (this is obviously bad)

Now when we want to refactor, it is difficult to understand how specific exceptions are supposed to be when handling different errors.

(I found surprisingly little information about this when googling).

I.e. a custom exception 'DataNotFoundException' seems incredibly broad, but can probably describe both the cases (empty content and deserialization).

On the other hand, 'ResposeContentNullException' and 'JsonDeserializationNullException' are very specific, but means that lots of them have to be created to cover all the cases.

Are there any rules or unwritten conventions that you good people of stack-overflow follow when creating, naming and using exceptions?

CodePudding user response:

Exceptions can be seen as a "special kind of return value". They are part of your method contract. If your methods are documented, that documenation should include a list of the exceptions that can be thrown and under which circumstances they are thrown (cf. this example from the base class library). Thus, in my opinion, exceptions should be designed/named with the caller of your method in mind.

In other words, ResposeContentNullException and JsonDeserializationNullException are much too specific, because they contain information about implementation details of your method---details which the caller of your method should not need to care about.

Instead, check the documentation and find out under which circumstances the response content can be null:

  • If the response content is null when a communication failure occurs, an IOException might be appropriate.

  • If the response content can never be null (according to the documentation), the user encountered a bug in your code and/or the base class library. In that case, an exception signaling that an assertion failed would be most appropriate. Unfortunately, there is none in the core libraries, so I personally (ab)use InvalidOperationException for that. A custom LogicErrorException, AssertionFailedException or ShouldNeverHappenException would be a cleaner solution.

  • Related