Avoiding null in C#






3.61/5 (21 votes)
Make Code More Robust by Avoiding nulls in C#
Introduction
The null
keyword is a special case for a variable value. Code robustness can be improved by reducing the number of special cases that have to be dealt with. In this article I shall explain how to reduce the number of times you use the null
keyword and thus (hopefully) improve the stability of your code.
Background
I come from a mainly C++ background. I C++ you can get so used to having to handle NULL
pointers that doing a check (if (MyClass != NULL)
) become second nature. After converting to C#, however, I realized that it was time to mend my ways. Having to check for null
every time I want to access a string or class clutters code and makes it more likely that other programmers in the future will end up getting lots of NullReferenceException
s to deal with.
Strings
With strings there are normally two special cases that have to be checked: null
strings and empty strings. Things are generally easier if we can reduce this to just one special case of empty strings.
When defining a string in a class, don't initialise it to null
. Instead, initialise it to the constant string.Empty
. This means that whenever another programmer accesses this string through a property, they don't have to worry about getting a null
value back.
However, you must also cope with the possibility that the user of the object passes a null
back in to the property. Therefore you must catch this and convert it to a null
.
For Example, the first of the following classes uses null
while the second does not:
// A naive, unstable class that uses nulls
public class MyUnstableStringClass
{
// Private string variable, initialised to null
private string mMyString = null;
// Simplistic property for accessing and modifying string.
public string MyString
{
get
{
return mMyString;
}
set
{
mMyString = value;
}
}
}
// A stable class that doesn't use nulls.
public class MyStableStringClass
{
// Private string variable, initialised to empty string.
private string mMyString = string.Empty;
// Public property for accessing and modifying string.
public string MyString
{
get
{
return mMyString;
}
set
{
if (value != null)
{
mMyString = value;
}
else
{
mMyString = string.Empty;
}
}
}
}
OK, so the second class has a few extra lines of code. That's the penalty for writing stable software, but it's not much. The advantage comes when the classes are used:
MyUnstableStringClass unstable = new MyUnstableStringClass();
MyStableStringClass stable = new MyStableStringClass();
// Check for empty strings
if (stable.MyString.Length == 0)
Console.WriteLine("Stable string is empty");
// THIS WILL THROW AN EXCEPTION (NullReferenceException)
if (unstable.MyString.Length == 0)
Console.WriteLine("Unstable string is empty");
// To prevent crash for unstable
if ((unstable.MyString != null) && (unstable.MyString.Length == 0))
Console.WriteLine("Unstable string is empty");
NOTE: To check for empty strings, use the Length
property, rather than comparing to the empty string. This is much faster than a string comparison.
You can see here that the MyStableStringClass.MyString
property doesn't need a null
-check to prevent a crash. This reduction in code required to use the class will more than make up for the additional few lines required within the class property. It will also help other programmers who may well forget to check for null
.
Classes
So far, so good. But strings are pretty simplistic; how can we use this for classes?
If you simply ensure that a class is properly initialised and that none of the properties return null
references, then we can use the same method as we used for strings in the first section of this article:
// A complex class containing properties that return simple classes
public class MyComplexClass
{
// Aggregated MyStableStringClass, available as a property
private MyStableStringClass mInternalClass = new MyStableStringClass();
// Access to the aggregated class
public MyStableStringClass InternalStringClass
{
get
{
return mInternalClass;
}
set
{
// Replace nulls with a new instance
if (value != null)
{
mInternalClass = value;
}
else
{
// If this class implemented IDisposable,
// we would call Dispose() here before re-initialising
mInternalClass = new MyStableStringClass();
}
}
}
}
As you can see, we initialise the aggregated class to a new instance (same as we set the string to be string.Empty
in the MyStableStringClass
in the first section of this article). In the InternalStringClass
property set
method, we replace null
references with new instances of the class. Now whenever we access the MyComplexClass.InternalStringClass
property, we never have to remember to check for null
; we can even go straight to MyComplexClass.InternalStringClass.MyString
and never have to worry that is might not exist.
Unfortuantely, there is a downside - you end up using more memory with this method. All classes are always instantiated, and this can become an issue in a system with a large number of classes. Fortunately, a more advanced solution has already been made: the NullObject (PDF file) pattern shows us how to create an equivalent of the string.Empty
constant for a class.
I won't go into the details of how to implement the NullObject pattern, I'll save that for another, more advanced article. Unless, of course, you feel inspired to write one first ...
Any comments are welcome. Any spelling mistakes are purely the readers reasonability.
History
- 19/06/2004 -- First release.