Hi,
This is a long one, so I'll summarize:
1. What are your opinions on raising an exception within the
constructor of a (custom) exception?
It seems unnecessary to me. Exceptions should provide information, not
validation. It shouldn't matter whether arguments are incorrect - that's
the caller's problem, IMO. Also, exceptions shouldn't depend on external
state either, so there should be no reason to throw exceptions at all from
within an exception's constructor.
If exceptions could be thrown, then all calling code would have to validate
arguments before passing them to Exception constructors. A bug in code that
doesn't validate the arguments correctly will not be easy to debug since a
caller might add a try..catch to catch some ArgumentNullException, for
instance, and inadvertently catch an ArgumentNullException from the buggy
method in which it called. There would be no way of knowing what the "real"
exception was going to be, especially if the exception is simply suppressed.
I've just posted a blog entry related to this topic that you might want to
look at (link after my sig).
Microsoft doesn't seem to provide any guidance on this topic, however.
"Designing Custom Exceptions"
http://msdn2.microsoft.com/en-us/library/ms229064.aspx
2. How do -you- validate arguments in your own exception constructors?
It's extremely rare that I create a custom exception, and when I do it's
always part of library code. I never throw an exception for invalid
arguments from within an exception's constructor, and I only consider an
argument to be invalid at all when it's null and I require a non-null
reference. In that case, I'll do something like: (arg == null) ?
string.Empty : arg.ToString(). In other words, use a default value.
I've noticed that, f.ex., ArgumentException accepts null arguments
without raising ArgumentNullException. Obviously, if nothing is to be
supplied to the exception constructor, the default constructor should
be called. What are your opinions on that type of error tolerance
within exception constructors?
- This will raise ArgumentException (and not ArgumentNullException even
though the argument is null):
throw new ArgumentException(null);
Here you're just setting the message parameter to null. In this case the
default message will be used by the exception class: "Exception of type
'System.ArgumentException' was thrown".
- Without a stack trace, I suppose the following would be tricky to
debug if argument validation raised exceptions within exception
constructors:
throw new ArgumentNullException(null);
If it were to have thrown an ArgumentNullException, the stack trace would
have provided that information. It wouldn't be obvious, however, and that's
why it doesn't make sense to throw an ArgumentNullException from a
constructor of the ArgumentNullException class itself.
What if I really want my custom exception to require that an empty
string may not be passed to the constructor? Let's say that I really
regard passing an empty string to the exception constructor as an
error, which would leave the exception in an erroneous state if it were
to be allowed...
If I have a custom exception called StringEmptyException and an empty
string is passed to the constructor of that exception, I would consider
raising the StringEmptyException - or at least ArgumentException (or
perhaps some other exception, like a custom
"InternalStringEmptyException").
But, it seems that exceptions are meant to be very tolerant - and I
would prefer that they were not.
StringEmptyException doesn't make sense. You should throw an
ArgumentException. For the sake of discussion, if you were to have a custom
StringEmptyException class, its constructor might accept a parameter named,
"paramName" just like ArgumentException, for instance. In that case, if the
caller decides to pass null then the StringEmptyException class itself can
proceed as normal since it doesn't actually require that argument to have a
non-null value - it's not using it for any particular processing logic. If
it did, and you tried to throw an ArgumentNullException, then somebody
calling into a method or setting a property to an empty string might end up
getting an ArgumentNullException, not realizing that that exception wasn't
intended to be thrown, and probably wasn't documented either since it's
really a bug. Very misleading.
--
Dave Sexton
http://davesexton.com/cs/blogs/blog/...ntingency.aspx