Background
A class reference may be null
, but in many cases a method that accepts a class reference as a parameter requires that the reference be non-null
.
(For the example snippets, we'll assume that returning 0
or -1
when a null
is passed is not desirable.)
The naive thing to do in such cases is to simply allow .NET to throw a NullReferenceException
the first time it is dereferenced:
public int CountOccurrences ( string String1 , string String2 )
{
}
But this doesn't tell the calling method which value is null
.
A smarter technique is to test the passed references, and throw a more informative exception:
public int CountOccurrences ( string String1 , string String2 )
{
if ( String1 == null )
{
throw new System.ArgumentNullException
( "String1" , "You must provide a string to search" ) ;
}
if ( String2 == null )
{
throw new System.ArgumentNullException
( "String2" , "You must provide a string to find" ) ;
}
}
But this performs the check on each parameter every time the method is called.
In most cases, this is fine, but in some cases this seems unnecessary. Consider a usage of this method that is used to count all the occurrences of some string
in the lines of a text file. In such a case, after reading each line, that line and the string
to find are passed to this method whereupon the references are checked for null
. That seems reasonable, but the second parameter will be checked on each call even though it doesn't change.
The test for null
doesn't impose much of a performance hit, so this isn't really a performance issue. I'm more concerned here with readability and maintainability; the second snippet above is safer than the first but is perhaps harder to read and maintain.
What if we could write the method as simply as the first example, but with the safety of the second? Maybe something like this:
public int CountOccurrences ( NonNullable<string> String1, NonNullable<string> String2 )
{
}
Implementation of My NonNullable<T> Structure
Unlike classes, struct
s can't be null
, so I'll use a struct
to wrap the class reference. Furthermore, wrapping a struct
in a NonNullable<T>
would be needless. So the beginning of our struct
looks like:
public struct NonNullable<T> where T : class
{
}
The struct
needs only one field; it'll hold the class reference. The value won't change, so we can make it readonly
, therefore we can also make it public
and avoid writing a property for it:
public readonly T Value ;
Only one constructor is required; it'll simply perform the check for null
and throw
or store:
public NonNullable
(
T Value
)
{
if ( Value == null )
{
throw ( new System.ArgumentNullException ( "Value" , "That value is null" ) ) ;
}
this.Value = Value ;
return ;
}
On second thoughts, many people don't like constructors that throw exceptions, so let's write one that won't throw
. This requires that we have a fall-back position that will still yield a valid instance. Something like this ought to do:
public NonNullable
(
T Value
,
NonNullable<T> IfNull
)
{
if ( Value == null )
{
this.Value = IfNull.Value ;
}
else
{
this.Value = Value ;
}
return ;
}
Every type should override ToString()
:
public override string
ToString
(
)
{
return ( this.Value.ToString() ) ;
}
By adding an implicit conversion to NonNullable<T>
, the calling method need not know what's going on:
public static implicit operator NonNullable<T>
(
T Value
)
{
return ( new NonNullable<T> ( Value ) ) ;
}
However, there is a performance hit involved. Worse than that, the guidelines for implicit conversions state that they shouldn't throw exceptions, and this one may. And, as with the naive non-checking method, the caller won't know which parameter was null
.
Add an implicit conversion from NonNullable<T>
for convenience:
public static implicit operator T
(
NonNullable<T> Value
)
{
return ( Value.Value ) ;
}
Lastly, a pair of Coalesce
methods to wrap the first non-null
reference among those provided:
public static NonNullable<T>
Coalesce
(
params T[] Values
)
{
return ( Coalesce ( (System.Collections.Generic.IEnumerable<T>) Values ) ) ;
}
public static NonNullable<T>
Coalesce
(
System.Collections.Generic.IEnumerable<T> Values
)
{
if ( Values == null )
{
throw ( new System.ArgumentNullException
( "Values", "No values were provided" ) ) ;
}
foreach ( T t in Values )
{
if ( t != null )
{
return ( new NonNullable<T> ( t ) ) ;
}
}
throw ( new System.ArgumentException
( "No non-null values were provided" , "Values" ) ) ;
}
Using the Code
Methods can be written as in the third snippet above:
public int CountOccurrences
( NonNullable<string> String1 , NonNullable<string> String2 )
{
}
And because I included the implicit conversion, the calling method doesn't need to know what the called method is doing. In fact, the called method could be rewritten to use NonNullable
parameters without affecting the caller.
A better practice, when calling a method that takes NonNullable
parameters is to wrap the value separately from making the call, especially when a value is used many times without changing.
...
int count = 0 ;
string line ;
NonNullable<string> safetext = new NonNullable<string> ( text ) ;
NonNullable<string> safeline
while ( ( line = file.Read() ) != null )
{
safeline = new NonNullable<string> ( line )
count += CountOccurrences ( safeline , safetext ) ;
}
...
(Note to self: Test with in
, out
, and ref
parameters.)
Performance
As stated above, this technique is not intended to improve performance; it is meant to reduce code and therefore maintenance. Having said that; my testing has shown a modest improvement in performance at best and a considerable performance hit at worst. After ten million calls to a method-that-takes-a-string
:
x 10000000 00:00:00.1204537 // with no check
x 10000000 00:00:00.1416811 // check the parameter on each call
x 10000000 00:00:00.3597213 // implicit conversion to NonNullable<string> on each call
x 10000000 00:00:00.2382019 // direct call to the NonNullable<string> constructor
// on each call
x 10000000 00:00:00.1083238 // call the NonNullable<string> constructor once
History
- 2008-04-11: First written