Argument validation within custom exception

M

matko

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?

2. How do -you- validate arguments in your own exception constructors?

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);

- 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);


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.
 
D

Dave Sexton

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.
 
M

matko

Thanks for taking the time!

I suppose a solution could be to use Debug.Assert to validate arguments
in some areas (since the caller is YOU (and often *only* you), and you
like working code, all arguments should validate properly, right?).

So, finally, I've come to the conclusion not to raise exceptions within
exception constructors!

However, I usually do that when it comes to argument validation in
methods as I really believe that passing invalid data to methods is an
exceptional error. In most cases.

Thx again!
 
D

Dave Sexton

Hi,
I suppose a solution could be to use Debug.Assert to validate arguments
in some areas (since the caller is YOU (and often *only* you), and you
like working code, all arguments should validate properly, right?).

Yes, that's not a bad idea for testing purposes. I think our perception of
exceptions differ from one another though. I see them as a container for
information. At the time of an exception, you'll want to see as much
available and applicable information as possible, so you commonly choose the
Type of exception that is appropriate and then supply the appropriate
arguments that your code has in scope. Any invalid information from the POV
of the caller should simply be considered as missing from the POV of the
exception, since its only job is to collect any information that is
available. That's why I feel that exceptions being thrown from within
exceptions doesn't make sense, regardless of any problems it may cause such
as the ones we've discussed already.
So, finally, I've come to the conclusion not to raise exceptions within
exception constructors!
:)

However, I usually do that when it comes to argument validation in
methods as I really believe that passing invalid data to methods is an
exceptional error. In most cases.

I completely agree. I think it's better to validate all method arguments,
unless your method doesn't depend on the state of the argument, such as when
a method simply forwards one argument to another method call.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top