Nullable Types in Generic Classes
Yea, I've run accross this too.
Your first attempt fails because when you use CBOField<int?>, you're actually saying CBOField<INullable<int>>. And since INullable is a reference type, not a value type it fails the struct constraint.
Your second attempt fails because INullable<T> constrains T to be a value type. Hmmm, I wish they hadn't done that.
Your third attempt fails because, well, string does not implement INullable<T>. Hmmm, that gives me an idea! What if you create a NullableString that implements INullable<?>?
Luckily for me, I had already created a bunch nullable types before I attempted to upgrade to 2.0. I started to replace them with the "new and improved" built in INullable, but didn't get very far because I ran into the same problems you have.
I know this post doesn't help much, but I hope it at least confirms your suspicions and gives you ideas on how to work around this issue.
[958 byte] By [
dkocur2] at [2007-12-16]
Keyser wrote: |
| I've tried using the constraint where T:INullableValue, however then I run into an issue with strings. |
|
I think we need to be a bit careful about what we mean by "nullable" versus "nullable type".
The introduction to the INullableValue interface [1] says this about "nullable":
Nullable is a characteristic of a type that means the type can be assigned a value or can be assigned null, which means the type has no value whatsoever. Consequently, a nullable type can represent data that exists and has a value, or data that does not exist at all. A reference type such as System.String is nullable, whereas a value type such as System.Int32 is not.
That is, reference types (like string) are inherently capable of being assigned a null value and don't need special support to be nullable. Value types (like int32) on the other hand are not capable of being assigned a null value and so the "Nullable Types" feature was introduced in 2.0 to provide support of the nullable characteristic for value types.
For most of the documentation "Nullable Type" seems to be used to refer specifically to the support for value types implementing the INullableValue interface usually by means of the System.Nullable<T> generic structure.
If we look at the Generic Nullable Structure definition [2] we see a couple of things that explain some of what you've seen
| | [SerializableAttribute()] public struct Nullable<T> : IFormattable, IComparable, INullableValue where T : ValueType |
Nullable<T> constrains T to be a value type so Nullable<string> or the equivalent <string?> is invalid because string as the parameter type fails to meet that constraint.
Also, Nullable<T> is of type struct (remember struct is a value type). Again, according to the INullableValue documentation [1]:
The System.INullableValue interface, the generic System.Nullable<> class, and the nongeneric System.Nullable class collectively support using a value type as a nullable type. Only value types can implement the System.INullableValue interface.
What this all boils down to (I think) is that you can't do what you want to do. You seem to want to declare a generic class with a type parameter constrained to the nullable characteristic - that is reference types and nullable value types would both be valid but non-nullable value types would not be valid.
I don't see any way to do that using generics.
You could constrain T to be a reference type (e.g., where T:class) and be able to use string as the type parameter but not int?. You could constrain T to be a nullable value type (e.g., where T:INullableValue) and be able to use int? as the type parameter but not string. But there's no way to constrain T to accept both.
It might be a nice additional feature to generics though. There may be a gotcha I haven't thought of but I think INullableValue and reference are close enough that you could usefully write generic code that would work for both.
Obviously you would have to avoid things like HasValue (since reference types don't implement INullableValue) but you could use == null as a test that would work for both.
Being able to specify a constraint that allowed the generic class to accept both reference types and nullable value types would let you do so while still getting the compiler to catch uses of non-nullable value types. It's a bit late in the day to get features added to VS 2005 but it might still be worth submitting the feature suggestion [3] if only for the future.
[1] http://msdn2.microsoft.com/library/7z42kf78(en-us,vs.80).aspx
[2] http://msdn2.microsoft.com/library/b3h38hb0(en-us,vs.80).aspx
[3] http://lab.msdn.microsoft.com/productfeedback/legal.aspx?fwd=sug