Is there a technical reason why there is no implicit conversion from DBNull to the various nullable and/or sql types? I understand why the conversions don’t currently happen, but don’t understand why an implicit conversion wasn’t created at the time or added in subsequent versions of the framework.
Just to be clear, I’m looking for technical reasons, not “because that’s they way they did it” or “I like it that way”.
Well, I don’t know about the
SqlTypescase, but there definitely are some technical reasons why adding an implicit conversion betweenDBNull.Valueand values ofNullable<T>withHasValue = falsewouldn’t work.Remember,
DBNullis a reference type, and despite the fact thatNullable<T>acts like a reference type — by pretending to be able to take on thenullvalue — it’s actually a value type, with value semantics.In particular, there’s a weird edge case when values of type
Nullable<T>are boxed. The behavior is special-cased in the runtime to box values of typeNullable<T>to a boxed version ofT, not a boxed version ofNullable<T>.As the MSDN documentation explains it:
Now we get into a tricky problem: the C# language spec (§4.3.2) says we can’t use an unboxing conversion to convert
DBNull.ValueintoNullable<T>:And we can’t use a user-defined conversion to convert from
objecttoNullable<T>, either, according to §10.10.3:OK, you or I couldn’t do it, but Microsoft could just amend the spec, and make it legal, right? I don’t think so.
Why? Well, imagine the intended use case: you’ve got some method that is specified to return
object. In practice, it either returnsDBNull.Valueorint. But how could the compiler know that? All it knows is that the method is specified to returnobject. And the conversion operator to be applied must be selected at compile time.OK, so assume that there is some magical operator that can convert from
objecttoNullable<T>, and the compiler has some way of knowing when it is applicable. (We don’t want it to used for every method that is specified to returnobject— what should it do if the method actually returns astring?) But we still have an issue: the conversion could be ambiguous! If the method returns eitherlong, orDBNull.Value, and we doint? v = Method();, what should we do when the method returns a boxedlong?Basically, to make this work as intended, you’d have to use the equivalent of
dynamicto determine the type at runtime and convert based on the runtime type. But then we’ve broken another rule: since the actual conversion would only be selected at runtime, there’s no guarantee that it would actually succeed. But implicit conversions are not supposed to throw exceptions.So at this point, it’s not only a change to the specified behavior of the language, a potentially significant performance hit, and on top of that it could throw an unexpected exception! That seems like a pretty good reason not to implement it. But if you need one more reason, remember that every feature starts out minus 100 points.
In short: what you really want here can’t be done with an implicit conversion anyway. If you want the behavior of
dynamic, just usedynamic! This does what you want, and is already implemented in C# 4.0: