(rewrote the answer to handle conversion among numeric types, along with their nullable and/or enumerable variations)
To handle the conversion between built-in numeric types, the Convert.ChangeType(object,Type) method will be your friend. Just make sure the value implements IConvertible interface (primitive .NET types like ints or doubles generally do).
When casting between enumerable and numeric types, Enum.ToObject(Type,object) should be used instead. The value given should match the enumerable underlying type, so to convert a decimal to integer-based int, an extra conversion will be necessary.
If string parsing is required, then Enum.Parse(Type,string) will be necessary for handling enumerable values. For plain numeric types, Convert.ChangeType should suffice, as long as you don't try to parse integer types from strings in decimal point format.
Finally, Convert.ChangeType doesn't work with nullable types, so the underlying type will need to be extracted first. Nullable.GetUnderlyingType(Type) is for just that.
Putting it all together, we can build an extended ChangeType method:
public static object ExtendedChangeType(object value, Type targetType)
{
if (value == null)
return null;
targetType = Nullable.GetUnderlyingType(targetType) ?? targetType;
if (targetType.IsEnum)
{
if (value is string)
{
return Enum.Parse(targetType, value as string);
}
else
{
value = Convert.ChangeType(value, Enum.GetUnderlyingType(targetType));
return Enum.ToObject(targetType, value);
}
}
else
{
return Convert.ChangeType(value, targetType);
}
}
Then we can use it like this:
PropertyInfo property = typeof(MyClass).GetProperty(nameof(MyClass.Id));
var value = ExtendedChangeType((int)1, valueType);
property.SetValue(myClassInstance, value);