views:

330

answers:

3

Consider the following sample code:

class SampleClass
{
    public long SomeProperty { get; set; }
}

public void SetValue(SampleClass instance, decimal value)
{
    // value is of type decimal, but is in reality a natural number => cast
    instance.SomeProperty = (long)value;
}

Now I need to do something similar through reflection:

void SetValue(PropertyInfo info, object instance, object value)
{
    // throws System.ArgumentException: Decimal can not be converted to Int64
    info.SetValue(instance, value)  
}

Note that I cannot assume that the PropertyInfo always represents a long, neither that value is always a decimal. However, I know that value can be casted to the correct type for that property.

How can I convert the 'value' parameter to the type represented by PropertyInfo instance through reflection ?

+10  A: 
void SetValue(PropertyInfo info, object instance, object value)
{
    info.SetValue(instance, Convert.ChangeType(value, info.PropertyType));
}
Thomas Levesque
that's the one, thanks!
jeroenh
Good stuff indeed!
CmdrTallen
A: 

As long as your value can be cast to the type the property needs then this should work properly. The runtime will convert the value as needed.

Look at the definition for PropertyInfo.SetValue. Notice that it takes an object argument, so any value you pass to the method will be boxed before it is passed to the property.

Rune Grimstad
This is not true. I tried it like that, and as stated in the question I got an ArgumentException. The runtime does not automatically convert a decimal to a long.
jeroenh
+2  A: 

The answer by Thomas is right, but I thought I would add my finding that Convert.ChangeType does not handle conversion to nullable types. To handle nullable types, I used the following code:

void SetValue(PropertyInfo info, object instance, object value)
{
    var targetType = info.PropertyType.IsNullableType() 
         ? Nullable.GetUnderlyingType(info.PropertyType) 
         : info.PropertyType; 
    var convertedValue = Convert.ChangeType(value, targetType);

    info.SetValue(t, convertedValue, null);
}

This code makes use of the following extension method:

public static class TypeExtensions
{
  public static bool IsNullableType(this Type type)
  {
    return type.IsGenericType 
    && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
  }
jeroenh