Click here to Skip to main content
Licence CPOL
First Posted 11 Apr 2008
Views 19,715
Downloads 49
Bookmarked 20 times

NonNullable Class Wrapper

By | 11 Apr 2008 | Article
A wrapper to place the burden of checking a class reference for null on the calling method rather than the called method.

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 )
{
    // Count the number of times String2 occurs in String1 and return that value
}

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

    // Count the number of times String2 occurs in String1 and return that value
}

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 )
{
    // Count the number of times String2 occurs in String1 and return that value
}

Implementation of My NonNullable<T> Structure

Unlike classes, structs 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
{
    // Members
}

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 )
{
    // Count the number of times String2 occurs in String1 and return that value
}

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 ;

// Check this value only once!
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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

PIEBALDconsult

Software Developer (Senior)

United States United States

Member

BSCS 1992 Wentworth Institute of Technology
 
Originally from the Boston (MA) area. Lived in SoCal for a while. Now in the Phoenix (AZ) area.
 
OpenVMS enthusiast, ISO 8601 evangelist, photographer, opinionated SOB
 
---------------
 
"Typing is no substitute for thinking." -- R.W. Hamming
 
"I find it appalling that you can become a programmer with less training than it takes to become a plumber." -- Bjarne Stroustrup
 
ZagNut’s Law: Arrogance is inversely proportional to ability.
 
"Well blow me sideways with a plastic marionette. I've just learned something new - and if I could award you a 100 for that post I would. Way to go you keyboard lovegod you." -- Pete O'Hanlon
 
"linq'ish" sounds like "inept" in German -- Andreas Gieriet
 

"Things would be different if I ran the zoo." -- Dr. Seuss
 
"Wrong is evil, and it must be defeated." – Jeff Ello
 
"A good designer must rely on experience, on precise, logical thinking, and on pedantic exactness." -- Nigel Shaw
 

"Omit needless local variables." -- Strunk... had he taught programming
 
"DON'T BE LIBERAL IN WHAT YOU ACCEPT!"
 
"Software Engineers don't have Trophy Wives; they have Presentation Layers."
 
"We learn more from our mistakes than we do from getting it right the first time."
 
"I'm an old dog and I like old tricks."
 
"Sometimes the envelope pushes back and sometimes you get a really nasty paper cut."
 
"A method shall have one and only one return statement."
 
My first rule of debugging: "If you get a different error message, you're making progress."
 
My golden rule of database management: "Do not unto others' databases as you would not have done unto yours."
 
My general rule of software development: "Design should be top-down, but implementation should be bottom-up."
 
"Today's heresy is tomorrow's dogma."
or
"Today's dogma is yesterday's heresy."
 
"The registry is evil."
 
"Every tool is a hammer."

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralNice Article about irritatable one Pinmemberthatraja11:23 15 Jan '10  
GeneralRe: Nice Article about irritatable one PinmvpPIEBALDconsult4:42 16 Jan '10  
GeneralExcellent Pinmember-Dy1:09 14 May '08  
GeneralRe: Excellent PinmemberPIEBALDconsult13:01 14 May '08  
GeneralNice PinmvpPete O'Hanlon9:46 13 Apr '08  
GeneralRe: Nice PinmemberPIEBALDconsult9:57 13 Apr '08  
GeneralUnfortunately, NonNullable.Value can be null [modified] PinmemberDaniel Grunwald1:24 12 Apr '08  
GeneralRe: Unfortunately, NonNullable.Value can be null [modified] PinmemberPIEBALDconsult3:54 12 Apr '08  
GeneralRe: Unfortunately, NonNullable.Value can be null [modified] PinmemberPIEBALDconsult4:28 12 Apr '08  
AnswerRe: Unfortunately, NonNullable.Value can be null PinmemberPete Appleton23:02 14 Apr '08  
GeneralRe: Unfortunately, NonNullable.Value can be null PinmemberMember 431986513:59 4 May '08  
I've overcome this by inheriting from new(), and changing the public readonly Value, to a getter/setter, where the getter will return a new T(), if fValue is null.
 
public struct NonNullable<T> where T : class, new()
{
...
/// <summary>The wrapped value.</summary>
public T Value
{
get { return fValue ?? new T(); }
private set { fValue = value; }
}
T fValue;
}


It does mean that the given class MUST have a parameterless constructor though. Frown | :(
 
I've also removed the need to pass a default value, again putting the onus on the calling method to ensure the passed value is not null. This is easily done by documenting the appropriate resultant syntax eg: NonNullable() b = class ?? (new class());
 
And one should also test for equality:
public override bool Equals(object obj)
{
if (!(obj is NonNullable<T> ))
{
return false;
}
 
return Equals((NonNullable<T> )obj);
}
 
public bool Equals(NonNullable<T> other)
{
return Value.Equals(other.Value);
}
 
public static bool operator ==(NonNullable<T> t1, NonNullable<T> t2)
{
return t1.Equals(t2);
}
 
public static bool operator !=(NonNullable<T> t1, NonNullable<T> t2)
{
return !t1.Equals(t2);
}
 
public override int GetHashCode()
{
return Value.GetHashCode();
}

 

I hope this helps...
GeneralRe: Unfortunately, NonNullable.Value can be null PinmemberDean Goddard14:06 4 May '08  
GeneralRe: Unfortunately, NonNullable.Value can be null PinmemberPIEBALDconsult16:51 4 May '08  
GeneralInteresting! PinprotectorMarc Clifton11:41 11 Apr '08  
GeneralRe: Interesting! PinmemberPIEBALDconsult12:00 11 Apr '08  
GeneralRe: Interesting! PinprotectorMarc Clifton12:21 11 Apr '08  
GeneralRe: Interesting! PinmemberPIEBALDconsult13:27 11 Apr '08  
GeneralRe: Interesting! PinmemberPIEBALDconsult14:58 11 Apr '08  
GeneralRe: Interesting! Pinmemberaspdotnetdev6:53 10 Sep '10  
GeneralRe: Interesting! PinmvpPIEBALDconsult15:45 11 Sep '10  
GeneralI wrote exactly the opposite code last nite! Pinmember leppie 11:22 11 Apr '08  
GeneralRe: I wrote exactly the opposite code last nite! PinmemberPIEBALDconsult11:37 11 Apr '08  
GeneralRe: I wrote exactly the opposite code last nite! Pinmember leppie 11:55 11 Apr '08  
GeneralRe: I wrote exactly the opposite code last nite! PinmemberPIEBALDconsult12:01 11 Apr '08  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120529.1 | Last Updated 11 Apr 2008
Article Copyright 2008 by PIEBALDconsult
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid