У меня есть код (который отлично работает), который выглядит примерно так:
int integer = 42;
decimal? castTo = integer;
Тогда я хотел сделать что-то подобное с отражением, с кодом, который выглядит следующим образом:
object value = source; // source was an int originally
var parameters = new object[1];
...
parameters[0] = value;
var setMethod = property.GetSetMethod();
// Call the set method, which takes a decimal? as a parameter
setMethod.Invoke(o, parameters);
Когда я делаю это, я получаю:
failed: System.ArgumentException : Object of type 'System.Int32' cannot be converted to type 'System.Nullable`1[System.Decimal]'.
at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
Почему неявное преобразование типов, которое отлично работает в других местах, перестало бы работать с отражением? Есть ли хитрость в использовании отражения для выполнения этого преобразования?
Редактировать : Спасибо всем за ответы. Вот решение, которое я придумал, основываясь на ответах:
private object Convert(object source, Type destinationType)
{
if (source == null)
{
return null;
}
var sourceType = source.GetType();
// unwrap nullable types
var nullableType = Nullable.GetUnderlyingType(destinationType);
if(nullableType != null)
{
destinationType = nullableType;
}
nullableType = Nullable.GetUnderlyingType(sourceType);
if(nullableType != null)
{
sourceType = nullableType;
}
var implicitCastMethod =
destinationType.GetMethod("op_Implicit",
new[] { sourceType } );
if(implicitCastMethod == null)
{
return null;
}
return implicitCastMethod.Invoke(null, new[] { source });
}
Редактировать # 2 : Я бы хотел, чтобы кто-то упомянул System.Convert.ChangeType()
, который обрабатывает эти случаи, и не только. Оказывается, что op_Implicit
может конвертировать только в менее строгие числовые типы. ( конечно , отсюда и «неявное» в названии). Другими словами, первое решение работало на int
& rarr; decimal?
но не decimal?
& rarr; int
. (Похоже, мне нужно изменить этот код, чтобы также попробовать op_Explicit
, если неявное приведение завершилось неудачно, если бы я хотел обрабатывать преобразование из decimal?
обратно в int
.)
Поскольку System.Convert.ChangeType()
не работает с Nullable<>
типами, я наконец-то использовал код, похожий на тот, который я нашел здесь (слегка измененный):
private static object Convert(object source, Type destinationType)
{
if(destinationType == null)
{
throw new ArgumentNullException("destinationType");
}
if(destinationType.IsGenericType &&
destinationType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (source == null)
{
return null;
}
destinationType = Nullable.GetUnderlyingType(destinationType);
}
return System.Convert.ChangeType(source, destinationType);
}