tags:

views:

13774

answers:

3

I want to do something like this :

myYear = record.GetValueOrNull<int?>("myYear"),

Notice the nullable type as the generic paramater.

Since the GetValueOrNull function could return null my first attempt was this :

public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName) where T : class
{
    object columnValue = reader[columnName];

    if (!(columnValue is DBNull))
    {
        return (T)columnValue;
    }
    return null;
}

But the error I get now is

The type 'int?' must be a reference type in order to use it as parameter 'T' in the generic type or method

Right! Nullable is a stuct! So I tried changing the class contstrainted to a stuct constrained (and as a side effect can't return null anymore) :

public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName) where T : stuct

Now the assingment

myYear = record.GetValueOrNull("myYear")

Gives the following error

The type 'int?' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method

Is specifying a nullable type as a generic parameter at all possible?

+26  A: 

Change the return type to Nullable, and call the method with the non nullable parameter

static void Main(string[] args)
{
    int? i = GetValueOrNull<int>(null, string.Empty);
}


public static Nullable<T> GetValueOrNull<T>(DbDataRecord reader, string columnName) where T : struct
{
    object columnValue = reader[columnName];

    if (!(columnValue is DBNull))
     return (T)columnValue;

    return null;
}
Greg Dean
My first answer was a bit too off-the-cuff here. I was just retyping my answer and this one appeared, nearly verbatim what i was going to say.
David Alpert
I suggest you use "columnValue == DBNull.Value" instead of the 'is' operator, because its slightly faster =)
driAn
Personal preference, but you can use the short form T? instead of Nullable<T>
RaceFace
+4  A: 

Just do two things to your original code. Remove the where constraint, and change the last return from return null to return default(T). This way you can return whatever type you want.

By the way, you can avoid the use of "is" by changing your if statement to if (columnValue != DBNull.Value).

Robert C. Barth
This solution does not work, as there is a logical difference between NULL and 0
Greg Dean
It works if the type he passes is int?. It will return NULL, just like he wants. If he passes int as the type, it will return 0 since an int can't be NULL. Besides the fact that I tried it and it works perfectly.
Robert C. Barth
A: 

Just had to do something incredible similar to this. My code:

public T IsNull<T>(this object value, T nullAlterative)
{
    if(value != DBNull.Value)
    {
        Type type = typeof(T);
        if (type.IsGenericType && 
            type.GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition())
        {
            type = Nullable.GetUnderlyingType(type);
        }

        return (T)(type.IsEnum ? Enum.ToObject(type, Convert.ToInt32(value)) :
            Convert.ChangeType(value, type));
    }
    else 
        return nullAlternative;
}
Toby