Search code examples
c#-4.0nullableunboxing

How to check type of unboxing nullable type with value = null?


Look at this method:

Dictionary<string,object> ViewModelParams = new Dictionary<string,object>();

AddParam(string paramKey,value)
{
    viewModelParams.Add(paramKey,value);
}

T GetParam<T>(string paramKey)
{
    if(viewModelParams[paramKey] is T)
        return (T)viewModelParams[paramKey];
    else
        throw exception...
}

For Nullable types the expression if(viewModelParams[paramKey] is T) , if value in dictionary was null, not worked properly, to clarify:

int? item=null;
AddParam("key",item);
GetParam<int?>("key")// throw exception because of 
                     // (viewModelParams[paramKey] is T) is false

I know concepts of boxing and unboxing for nullable type(Boxing Nullable Types), but i don't know which expression replaced with if(viewModelParams[paramKey] is T) for this scenario?


Solution

  • The problem is that if the value is null, then it has no type and is will return false whatever you pass it. The only way the runtime could tell what type was in the dictionary value is if it wasn't null.

    I think the best you could do here is a couple of overloads of your GetParam method:

    T? GetParam<T>(string paramKey) where T : struct
    {
        object value = viewModelParams[paramKey];
        if (value == null) return null;
    
        if(value is T)
            return (T?)value;
        else
            throw exception...
    }
    
    T GetParam<T>(string paramKey) where T : class
    {
        object value = viewModelParams[paramKey];
        if (value == null) return null;
    
        if(value is T)
            return (T)value;
        else
            throw exception...
    }
    
    

    I've taken a couple of liberties here:

    1. I've changed the signature such that when you request value type T you actually get T?. In your example you'd call GetParam<int> rather than GetParam<int?>.
    2. If the value in the dictionary is null, I'm returning null, rather than throwing an exception. This is a change in behaviour, even if your T is a reference type. I think this is the behaviour you really wanted, as you were demonstrating attempting to store an int?.

    Of course, you have probably worked around this issue now, ten years after you asked the question!