A common problem in any language is to assert that parameters sent in to a method meet your requirements, and if they don\'t, to send nice, informative error messages. This
I tackled this exact problem a few weeks ago, after thinking that it is strange how testing libraries seem to need a million different versions of Assert
to make their messages descriptive.
Here's my solution.
Brief summary - given this bit of code:
int x = 3;
string t = "hi";
Assert(() => 5*x + (2 / t.Length) < 99);
My Assert function can print out the following summary of what is passed to it:
(((5 * x) + (2 / t.Length)) < 99) == True where
{
((5 * x) + (2 / t.Length)) == 16 where
{
(5 * x) == 15 where
{
x == 3
}
(2 / t.Length) == 1 where
{
t.Length == 2 where
{
t == "hi"
}
}
}
}
So all the identifier names and values, and the structure of the expression, could be included in the exception message, without you having to restate them in quoted strings.
The Lokad Shared Libraries also have an IL parsing based implementation of this which avoids having to duplicate the parameter name in a string.
For example:
Enforce.Arguments(() => controller, () => viewManager,() => workspace);
Will throw an exception with the appropriate parameter name if any of the listed arguments is null. It also has a really neat policy based rules implementation.
e.g.
Enforce.Argument(() => username, StringIs.Limited(3, 64), StringIs.ValidEmail);
Don't know if this technique transfers from C/C++ to C#, but I've done this with macros:
#define CHECK_NULL(x) { (x) != NULL || \ fprintf(stderr, "The value of %s in %s, line %d is null.\n", \ #x, __FILENAME__, __LINE__); }
In this case, rather than use your own exception type, or really general types like ApplicationException.. I think it is best to use the built in exception types that are specifically intended for this use:
Among those.. System.ArgumentException, System.ArgumentNullException...
My preference would be to just evaluate the condition and pass the result rather than passing an expression to be evaluated and the parameter on which to evaluate it. Also, I prefer to have the ability to customize the entire message. Note that these are simply preferences -- I'm not saying that your sample is wrong -- but there are some cases where this is very useful.
Helper.Validate( firstName != null || !string.IsNullOrEmpty(directoryID),
"The value for firstName cannot be null if a directory ID is not supplied." );
Here's my answer to the problem. I call it "Guard Claws". It uses the IL parser from the Lokad Shared Libs but has a more straightforward approach to stating the actual guard clauses:
string test = null;
Claws.NotNull(() => test);
You can see more examples of it's usage in the specs.
Since it uses real lambdas as input and uses the IL Parser only to generate the exception in the case of a violation it should perform better on the "happy path" than the Expression based designs elsewhere in these answers.
The links are not working, here is the URL: http://github.com/littlebits/guard_claws/