9

I have some class with some properties and I want to convert values from string to type of this properties. And I have problem with conversion to nullable types. This is my method for converting:

public static object ChangeType(object value, Type type)
{
    if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
    {
        if (value == null)
        {
            return null;
        }

        var underlyingType = Nullable.GetUnderlyingType(type);
        var val = Convert.ChangeType(value, underlyingType);
        var nullableVal = Convert.ChangeType(val, type); // <-- Exception here
        return nullableVal;
    }

    return Convert.ChangeType(value, type);
}

I'm getting exception like this (for property of type int?):

Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.

How can I convert from type to nullable type? Thanks.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
Vitone
  • 498
  • 1
  • 7
  • 19

2 Answers2

10

It is impossible... Boxing of value types "erases" the Nullable<> part...

int? num = 5;
object obj = num;
Console.WriteLine(obj.GetType()); // System.Int32

and

int? num = null;
object obj = num;
Console.WriteLine(obj == null); // True

Note that this characteristic is what makes Nullable<> "special". They need direct support from the CLR. Nullable<> isn't simply a struct that you could write.

What you can do:

public static object ChangeType(object value, Type type)
{
    // returns null for non-nullable types
    Type type2 = Nullable.GetUnderlyingType(type);

    if (type2 != null)
    {
        if (value == null)
        {
            return null;
        }

        type = type2;
    }

    return Convert.ChangeType(value, type);
}
xanatos
  • 109,618
  • 12
  • 197
  • 280
2
var nullableVal = Activator.CreateInstance(type, val);

Using the activator will allow you to create a new instance of the int? class with an argument being passed to the constructor of the int value. The below code is a literal demonstration of such:

var type = typeof(int?);

var underlyingType = typeof(int);

var val = 123;

var nullableVal = Activator.CreateInstance(type, val);
Will Custode
  • 4,576
  • 3
  • 26
  • 51