Writing a good Debug.Assert

I find it interesting that even after working on .NET code for years, I still keep evolving my usage of the platform and style. Today's post is an example of such a thing.

Hopefully you already know about the Debug.Assert API. This allows you to make assertions about how your code behaves, and works only on debug builds (technically, on any build that defines DEBUG). On release builds, this call (and the calls used to build up its arguments) are compiled out of the binary.

This means, for example, that it's appropriate to use it to check locally what has already been checked elsewhere, but it shouldn't be used to check parameters on public method - you'd want a real check with an exception thrown for the latter case.

One of the overloads for the Assert method takes the condition to be asserted and a message to output. A good message is very useful, as it helps you to track down exactly what went wrong.

Typically I start my assertion messages with the condition, especially for something simple. Here's an example.

public void Foo(string text) {
if (text == null) throw new ArgumentNullException("text"); // remember this is public!
InternalFoo(text);
}
private void InternalFoo(string text) {
Debug.Assert(text != null, "text != null");
Console.WriteLine("Value: " + text);
}

This example shows that for simple parameter checks, the assertion text is probably enough. If the assertion fires, you'll get a stack trace leading to the method with the assertion, and the message identifying which parameter failed.

For non-trivial cases (pretty much anything that isn't a direct fault of the caller with a bad argument), I like to include a short explanation that gives an idea of (a) why I think the check should be an assertion rather than a runtime check, and (b) who is to blame.

A classis non-trivial example is when a value is captured in one method but used in another. For example, let's say we have a Foo class that can write its argument to the console, but takes the argument in the constructor. Here's how we might code it.

public class Foo {
private readonly string textField;
public Foo(string text) {
if (text == null) throw new ArgumentNullException("text");
this.textField = text;
}
public void WriteItOut() {
Debug.Assert(this.fieldText != null, "this.fieldText != null -- otherwise .ctor should have thrown an exception");
Console.WriteLine("Value: " + this.fieldText);
}
}

This is the typical format I'll use - first the assertion code, then a little separator and an "otherwise" explanation, pointing to who I think should have checked this before. Of course this isn't infallible - for example, if textField later changes to not being readonly and a different method changes the field to null after the constructor has run, then the assertion might be misleading. But in general (more so the more consistent you are in validation designs), the assertion message is a very good hint, one that may often save you from even having to fire a debugger to figure out where your bug is.

Enjoy!