tags:

views:

242

answers:

5

C# 2.0 gives me access to nullable types. This seems very convenient when I want the DateTime variable in the database to be null. Is there anything I should worry about when using nullable types or can I go overboard and make every type I have nullable?

+4  A: 

Watch out for DBNull which is different to null

Mitch Wheat
+7  A: 

Mitch's DBNull not being null is a good point. Also beware of this, which is legal C# but will (fortunately) produce a warning:

int x = 0;

// Much later
if (x == null)

It looks like it should be illegal, but it's valid because x can be implicitly converted to a nullable int. Never ignore this warning.

You should also be aware of what appear on the surface to be oddities with operators. For instance, usually you'd expect that:

if (x <= y || x >= y)

would always be true - but it's not when x and y are both null. However, x == y will be true - unlike in SQL and indeed unlike VB! The lifted operator behaviour is provided by the language, not the runtime, so you need to be aware of what each language you use will do.

Finally, make sure you understand how boxing works with nullable types. A non-null value of a nullable value type is boxed as if it were non-nullable to start with, and a null value is boxed to a simple null reference. (i.e. no box is actually created - the runtime just returns null). You can unbox to a nullable value type from either a null reference or a box of the underlying type. Does that make sense? (I go into it in more detail in C# in Depth, and hopefully with a bit more clarity... but it's 8.45 and I haven't had coffee...)

EDIT: Okay, maybe an example will help:

int? i = 5;
int? j = null;

object x = i; // x = reference to boxed int (there's no such thing as a "boxed nullable int")
object y = j; // y = null (a simple null reference)

i = (int?) x; // Unboxing from boxed int to int? is fine.
j = (int?) y; // Unboxing from a null reference to int? is fine too.
Jon Skeet
@Jon, Last paragraph "Does that make sense?", Answer: no. ;) It's 8:55 I've not had coffee either, perhaps it will later.
AnthonyWJones
Will add example to help.
Jon Skeet
+1  A: 

You should also be careful to only use nullable types where the logic of the class mandates that the values are really nullable. This may sound stupid, but if you "go overboard" and make everything nullable you may be making the code more complex than necessary.

When it's used at the appropriate places I think it improves code quality, but if it's redundant, don't do it.

krosenvold
A: 

There is a gotcha with GetType(), that is particularly apparent when using new() and generics to watch for:

static void Foo<T>() where T : new()
{
    T t = new T();
    string s = t.ToString(); // fine
    bool eq = t.Equals(t); // fine
    int hc = t.GetHashCode(); // fine
    Type type = t.GetType(); // BOOM!!!
}

Basically, GetType() is unusual in that it isn't virtual, so it always gets cast (boxed) to object. The unusual boxing rules mean that this calls GetType() on null, which isn't possible. So void calling GetType() if you think you might have empty Nullable<T> objects.

Also - note that some data-binding methods don't like Nullable<T> very much.

Marc Gravell
I should have clarified, the Foo example applies when T is (for example) `int?`
Marc Gravell
A: 

Interoperability can be a problem - e.g. exposing to COM clients or as a web service.

Joe