I'm trying to set the value of a property TargetProp
of type TargetPropType
of a framework via reflection in C#.
The property seems to be a container for doubles which enrich the double with units.
Doing the following works
parentOfProperty.TargetProp = 5.0;
While the following fails with a System.ArgumentException "Object of type 'System.Double' cannot be converted to type 'TargetPropType'."
PropertyInfo setProperty = parentOfProperty.GetType().GetProperty("TargetProp");
setProperty.SetValue(parentOfProperty, 5.0, null);
The following also fails with the same exception
setProperty.GetSetMethod()?.Invoke(parentOfProperty, new object[] { 5.0 });
What could be different in the first assignment that it works while the reflection assignments fail?
Setting the property directly to double
works but using reflection doesn't, because the type of the property has an implicit conversion from int
, as you linked in the comments. Reflection doesn't resolve implicit conversion operators.
So you can just call the implicit conversion operator manually, and pass the result to SetValue
:
TargetPropType arg = 5.0;
setProperty.SetValue(parentOfProperty, arg, null);
However it seems like you want a more general solution. From the comments:
The program reads an input file and a transformation file. The
TargetProp
is given by the transformation file and can be any property in the framework. At runtime the program only knows that some value must be converted toTargetProp
.
I would recommend using a Dictionary<Type, Func<object, object>>
to record exactly how to create each type of property that you may encounter. Let's call this conversionsDict
. For example, conversionsDict
would have an entry where the key is typeof(TargetPropType)
, and the value is something like:
o => {
TargetPropType result = (double)o; // assuming only doubles can get converted to TargetPropType
return result;
// or simply "return new TargetPropType((double)o)" if that's what the implicit conversion does
}
You can put all the types that require a conversion in conversionsDict
, and do:
PropertyInfo setProperty = parentOfProperty.GetType().GetProperty(someStringYouGetFromTransformationFile);
Type propertyType = setProperty.PropertyType;
object value = theValueYouWantToSet;
if (conversionsDict.TryGetValue(propertyType, out var converter)) {
value = converter(value);
}
setProperty.SetValue(parentOfProperty, value, null);
Alternatively, you can use reflection to call the implicit conversion operator. The operator compiles to a method in IL called op_Implicit
, though I'm not sure if this is specified anywhere.
// list out the primitive types that needs no conversion
var listOfPrimitives = new List<Type>() { ... };
object value = theValueYouWantToSet;
if (!listOfPrimitives.Contains(propertyType)) {
var method = propertyType.GetMethod("op_Implicit", new[] { value.GetType() });
if (method != null) {
value = method.Invoke(null, new[] { value });
}
}
setProperty.SetValue(parentOfProperty, value, null);
See also this post which uses the TypeDescriptor
API.