If you’ve followed any of my posts you’ll know that I get a lot of posts from problems that I face and the solutions that I come up with. This post is no exception. I ran into an issue trying to create an extension method using generics. (e.g System.Nullable<T> or System.Nullable(Of T))
I had a value coming back from a LINQ to SQL stored proc call that was defined as a nullable type (System.Nullable(Of Byte)). When I went to set the .Text property of one of my textboxes I was presented with this error: “Nullable object must have value”
Textbox1.Text = myObject.Property.Value ‘error occurs here
Ok. I’ve seen that error before. But why am I getting it now? A quick google search and I quickly remembered that you can’t use the “value” method of a nullable type if the “value” is null. Weird but that’s the behavior.
I obviously wanted to fix this problem so I started off by writing this code:
TextBox1.Text = If (myValue.HasValue, myValue.Value.ToString(), string.Empty)
That was ok but I would have had to repeat the same code all of the place in my project. I’m not a big fan of copy / paste. I’d rather write a method to do this. My next thought was to write an extension method to handle the conversion. That way I can simply write something like:
TextBox1.Text = myValue.ToNullableString()
However, I only wanted to write one extension method. I COULD write a bunch of extension methods for each type that I would ever return from the db (i.e. byte, int32, Int16, etc). Some of those would look like this:
C#
public static string ToNullableString(this System.Nullable<Int32> param)
{
// implementation here
}
public static string ToNullableString(this System.Nullable<byte> param)
{
// implementation here
}
VB
Public Function ToNullableString(ByVal param As System.Nullable(Of Int32)) As String
‘ implementation here
End Function
Public Function ToNullableString(ByVal param As System.Nullable(Of Byte)) As String
‘ implementation here
End Function
Well I certainly don't want to write a method for each type that can be return from the database. I only wanted to write ONE method. That means I’m going to creating a generic method. I thought “Can I even write an extension method for a generic type?”. Come to find out that you can. It just takes a little more work.
As you SHOULD already know (i
f not, click here) the first parameter in an extension method is the type being extended. For this extension method I needed the parameter to be of type System.Nullable(Of T). My first iteration of the method looked like this:
C#
public static string ToNullableString(this System.Nullable<T> param)
{
//implementation
}
VB
Public Function ToNullableString(ByVal param As Nullable(Of T)) As String
‘ implementation
End Function
But with this version I received an error stating “Type T is not defined” in VB and “The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?” in C#.
Make sense, I haven’t defined what “T” should be yet. Next I tried this:
VB
Public Function ToNullableString(Of T)(ByVal param As Nullable(Of T)) As String
End Function
C#
public static string ToNullableString<T>(this System.Nullable<T> param)
{
//implementation
}
Well, that didn’t work either. This time I received this error in VB “Type 'T' must be a value type or a type argument constrained to 'Structure' in order to be used with 'Nullable' or nullable modifier '?'.” and this error “The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable<T>'” in C#.
After reviewing my
Pro C# book I figured out what the solution was. I needed to use the “where” constraint. In our case the constraint will be for “struct” or “Structure”. This tells the compiler to only allow this method to be used by types that have System.ValueType in its chain of inheritance. These are the final iterations of the method:
C#
public static string ToNullableString<T>(this System.Nullable<T> param) where T : struct
{
if (param.HasValue)
{
return param.Value.ToString();
}
else
{
return string.Empty;
}
}
VB
<Extension()> _
Public Function ToNullableString(Of T As Structure)(ByVal param As Nullable(Of T)) As String
If (Not param.HasValue) Then
Return String.Empty
Else
Return param.Value.ToString
End If
End Function
You'll notice that the "where" constraint is defined as "As Structure" in vb.
So now I can use the code like this:
Dim myValue As System.Nullable(Of Integer) = GetValueFromLinqToSql()
TextBox1.Text = myValue.ToNullableString() ‘ now we don’t get an error!
Hope this helps anyone else that has run into a similar problem.