DBNull is my Nemisis: Part Deux

Posted on May 12, 2008

******
This is the second part of my rant about DbNull. Go here to read the first part.
******

Ok. So now you have a utility method that lets you check for null whether it’s null, DbNull, or, if bound to a datagrid, “ ”

What if you want to Convert that object, which might be null or DbNull, to a Type? What if you’d like to write it in pretty code? Well then you’d use this lovely method:


public static T ConvertToType(object o)
{
if (o == DBNull.Value || o == null)
return default(T);
return (T)o;
}

There are few things to note about this method. The first is that it will throw an exception if o can’t be cast to type T. This very possibly might be what you want.

The second thing to note is the use of default(T). The default method is a useful little thing that allows .Net Generics to work with both value (structs) and reference (class) types. Basically, default(T) will return the default value of a value type, i.e. 0 for int or System.Int32, or null for a reference Type.

What if you don’t want the method to throw an exception when converting? What if you’d like to use the equivalent to the “as” operator?

You might replace the last line of the method with this:


return o as T;

Then you would get a compiler error. Why? It’s quite simple really. The “as” operator only works on reference types because only reference types can be null. One solution to this problem is to return default(T) if the casting fails.


public static T ConvertToTypeOrDefault(object o)
{
try
{
return ConvertToType(o);
}
catch (Exception e)
{
//this will return null for nullable types & the default value for non-nullable types
return default(T);
}
}

However, what if you really really want the convert method to return null. The short answer is that you can’t; the long answer is that you can. 🙂

While you can’t make a method that could return value types return null, you can force the method to only take certain Types using Generic constraints. In this case, we’d want the method to only accept reference types.

I tried to get this to work using a variety of methods until my trial and error finally ended in success. First, I tried returning T? (i.e. Nullable) but since reference types are already Nullable and Generic Nullable class only takes value types. Bah. So I tried restricting T to System.Nullable. Nope – static classes can’t be used as constraints. Then, I tried restricting T to System.Object. Nope – Object is a special class and can’t be used in this way. (Awww, it’s special) . Next, I tried constraining T to new(), which essentially constrains T to classes that have a default constructor. Still nada – constraining to new() had no effect on the compiler erroring when I tried to return null.

Finally, after skimming the MSDN introductory article on Generics, I landed on the solution! T can be constrained by “class” (and conversely, by struct).


public static T ConvertToTypeOrNull(object o) where T : class
{
if (o == DBNull.Value)
return null;
return o as T;
}

Viola!

It’s true that the ConvertTypeToDefault method is essentially the same for ConvertTypeToNull when T is a class. One advantage of using the ConvertTypeToNull is that it doesn’t require the overhead of exception handling.

Thinking about default and value types brings up another issue though: What if you want to know if something is null OR if it’s the default value. In other words, you are converting the Potential-DbNull object to a struct and want to know if it has no value.

You could add an additional method:



public static bool isNullOrDefault(object o)
{
bool bIsNull = isNull(o);
if (!bIsNull && o is ValueType)
{
bIsNull = ConvertToType(o).Equals(default(T));
}
return bIsNull;
}

public static bool isNullOrDefault(object o, bool webBound)
{
bool bIsNull = isNull(o, webBound);
if (!bIsNull && o is ValueType)
{
bIsNull = ConvertToType(o).Equals(default(T));
}
return bIsNull;
}

Something to note is that I’m not using the == operator to compare the default type with what’s returned by ConvertToType. Why? Simple – the compiler doesn’t let me. Again, because at compile-time the type that T represents is ambiguous, the compiler doesn’t know if T supports the use of the == operator so it complains. Fortunately, the Java style .Equals method, while a bit ugly, does the trick just fine.

Also, the above method will throw an exception if the object can’t be converted to the type. It seems logical to me, but you could use a different ConvertToType* method if you wanted.

(If you want to know more about what the webBound bool is for, check out my first post on DbNull.)

So there you have it! A DbNullUtility class to make your life just a little bit easier. Hooray for me and fuck DbNull! (Bad Religion anyone??)


No Replies to "DBNull is my Nemisis: Part Deux"


    Leave a Reply

    This site uses Akismet to reduce spam. Learn how your comment data is processed.