In my code I have often situations like this:
public void MyMethod(string data)
{
AnotherClass objectOfAnotherClass = GetObject(data);
if (objectOfAnotherClass == null)
throw new WhatExceptionType1("objectOfAnotherClass is null.");
if (objectOfAnotherClass.SomeProperty < 0)
throw new WhatExceptionType2("SomeProperty must not be negative.");
}
Imagine that GetObject makes use of some external libraries which are not under my control and that this library returns null if no object for data exists and considers a negative SomeProperty as a valid state and therefore doesn’t throw an exception. Further imagine that MyMethod cannot work without objectOfAnotherClass and does not make sense with a negative SomeProperty.
What are the proper exceptions for WhatExceptionType1/2 to throw in this situation?
Basically I had four options in mind:
-
1)
InvalidOperationException, becauseMyMethoddoesn’t make sense under the conditions described above. On the other hand the guidelines (and Intellisense in VS too) say that an InvalidOperationException should be thrown if the object the method belongs to is in an invalid state. Now the object itself isn’t in an invalid state. Instead the input parameterdataand some other operations based on this parameter lead to a situation whereMyMethodcannot operate anymore. -
2)
ArgumentException, because there are values fordatathe method can work with and other values the method can’t. But I cannot check this by inspectingdataalone, I have to call other operations before I decide. -
3)
Exception, because I don’t know which other exception type to use and because all other predefined exceptions feel too specialized and not fitting to my situation. -
4)
MyCustomException(my own exception type derived fromException). This seems always an option but I am worried that I have to define lots of special exception classes for many different error conditions when I start to follow this pattern.
Are there other and better options? What are the arguments in favor or against those options?
Thank you for feedback in advance!
Be careful when using built-in exception types… they have very specific meanings to the .NET framework, and unless you are using it for exactly the same meaning, it’s better to roll your own (+1 to John Saunders for
Serializeable).InvalidOperationExceptionhas the meaning:For example, if you call
SqlConnection.Open(), you get anInvalidOperationExceptionif you haven’t specified a data source.InvalidOperationExceptionisn’t appropriate for your scenario.ArgumentExceptionisn’t appropriate, either. The failure to createobjectOfAnotherClassmay have nothing to do with bad data being passed in. Suppose it’s a filename, butGetObject()doesn’t have permissions to read the file. As the method is written, there’s no way to know why the call toGetObject()failed, and the best you can say is the object returned was null or invalid.Exceptionis just a bad idea, in general… it gives the caller absolutely no idea why the method failed to create the object. (For that matter, having only acatch (Exception ex) {..}is a bad idea, too)You want exceptions that clearly identify what went wrong, and that means creating your own. Try to keep them generic to avoid 1,000 custom exceptions. I suggest:
Thanks for the vote ~ thought I would add an example of some custom exceptions we’ve written.
Note that you don’t really need to add any code to the methods, because the custom exceptions don’t really do anything differently than their base classes; they just represent something different. The second example does add a property to the exception, so there’s code to support it (including constructors).
The first is a generic base for all of our exceptions; the rule “Don’t catch general Exceptions” applies (though we do it anyway… it allows us to differentiate between exceptions we generated and exceptions thrown by the framework). The second is a more specific exception that derives from
Gs3Exceptionand serializes a custom property.The .NET development team decided
ApplicationExceptionhad no real-world value and deprecated it, but the purist in me always liked it, so it persists in my code. Here, though, it really does add no value and only increases the depth of the inheritance heirarchy. So feel free to inherit directly fromExceptioninstead.PS: Before anyone calls me on it, the reason for a base
Gs3Exceptionthat adds no more value than theApplicationExceptionis the Enterprise Library Exception Handling Application Block… by having an application-level base exception, we can create general logging policies for exceptions thrown directly by our code.