'casting' with reflection
Solution 1
void SetValue(PropertyInfo info, object instance, object value)
{
info.SetValue(instance, Convert.ChangeType(value, info.PropertyType));
}
Solution 2
Thomas answer only works for types that implement IConvertible interface:
For the conversion to succeed, value must implement the IConvertible interface, because the method simply wraps a call to an appropriate IConvertible method. The method requires that conversion of value to conversionType be supported.
This code compile a linq expression that does the unboxing (if needed) and the conversion:
public static object Cast(this Type Type, object data)
{
var DataParam = Expression.Parameter(typeof(object), "data");
var Body = Expression.Block(Expression.Convert(Expression.Convert(DataParam, data.GetType()), Type));
var Run = Expression.Lambda(Body, DataParam).Compile();
var ret = Run.DynamicInvoke(data);
return ret;
}
The resulting lambda expression equals to (TOut)(TIn)Data where TIn is the type of the original data and TOut is the given type
Solution 3
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(instance, 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<>));
}
}
Solution 4
Contributing to jeroenh's answer, I would add that Convert.ChangeType crashes with a null value, so the line for getting the converted value should be:
var convertedValue = value == null ? null : Convert.ChangeType(value, targetType);
Solution 5
When the Type is a Nullable Guid then none of the above proposed solutions work.
Invalid cast from 'System.DBNull
' to 'System.Guid
' exception is thrown at Convert.ChangeType
To fix that change to:
var convertedValue = value == System.DBNull.Value ? null : Convert.ChangeType(value, targetType);
Comments
-
jeroenh over 1 year
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 ?
-
jeroenh about 11 yearsThis problem is not specific to Guid but rather due to the fact that you get
DBNull.Value
instead of simplynull
when fetching null values from the database through ADO.Net. You will see the same with nullable int, for example. -
jnm2 over 9 yearsThis is actually the answer I came looking for. Non-IConvertible dynamic casting.
-
jnm2 over 9 yearsHeh I would- if I was OP.
-
derekantrican over 3 yearsNote that
Convert.ChangeType(value, property.PropertyType);
can still fail ifvalue
does not implement theIConvertible
interface. For instance, ifinfo.PropertyType
is someIEnumerable
-
derekantrican over 3 yearsWas hoping this would save me when trying to cast
IEnumerable<object>
(where those objects are strings) toIEnumerable<string>
. Unfortunately I'm getting errors likeUnable to cast object of type 'System.Collections.Generic.IEnumerable'1[System.Object]' to type 'System.Collections.Generic.IEnumerable'1[System.String]'.
-
shtse8 about 3 years@derekantrican you need to iterate the list and cast each by your self.
-
DDRider62 about 2 yearsI know this question is old, but also notice that Convert.ChangeType can return a different value than plain casting. For example,
double d = 5.57293; int i = Convert(d, typeof(int))
will return 6. But doingint i = (int)d
will return 5.