У меня есть код (который отлично работает), который выглядит примерно так:
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
→ decimal?
, но не decimal?
→ 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);
}