다음 샘플 코드를 고려하십시오.
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;
}
이제 반사를 통해 비슷한 작업을 수행해야합니다.
void SetValue(PropertyInfo info, object instance, object value)
{
// throws System.ArgumentException: Decimal can not be converted to Int64
info.SetValue(instance, value)
}
PropertyInfo가 항상 long을 나타내고 그 값이 항상 10 진수가 아니라고 가정 할 수는 없습니다. 그러나 값이 해당 속성에 대한 올바른 유형으로 캐스팅 될 수 있음을 알고 있습니다.
리플렉션을 통해 ‘value’매개 변수를 PropertyInfo 인스턴스가 나타내는 유형으로 어떻게 변환 할 수 있습니까?
답변
void SetValue(PropertyInfo info, object instance, object value)
{
info.SetValue(instance, Convert.ChangeType(value, info.PropertyType));
}
답변
Thomas 대답은 IConvertible 인터페이스를 구현하는 유형에서만 작동합니다.
변환이 성공하려면 값이 IConvertible 인터페이스를 구현해야합니다. 메서드가 적절한 IConvertible 메서드에 대한 호출을 단순히 래핑하기 때문입니다. 이 메서드를 사용하려면 값을 conversionType으로 변환 할 수 있어야합니다.
이 코드는 unboxing (필요한 경우) 및 변환을 수행하는 linq 표현식을 컴파일합니다.
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;
}
결과 람다 식은 (TOut) (TIn) Data와 같습니다. 여기서 TIn은 원본 데이터의 유형이고 TOut은 주어진 유형입니다.
답변
Thomas의 대답은 옳지 만 Convert.ChangeType이 nullable 형식으로의 변환을 처리하지 않는다는 내 결과를 추가 할 것이라고 생각했습니다. nullable 형식을 처리하기 위해 다음 코드를 사용했습니다.
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);
}
이 코드는 다음 확장 메서드를 사용합니다.
public static class TypeExtensions
{
public static bool IsNullableType(this Type type)
{
return type.IsGenericType
&& type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
}
답변
jeroenh의 답변에 기여하여 Convert.ChangeType이 null 값과 충돌하므로 변환 된 값을 가져 오는 줄은 다음과 같아야합니다.
var convertedValue = value == null ? null : Convert.ChangeType(value, targetType);
답변
Type이 Nullable Guid이면 위에 제안 된 솔루션 중 어느 것도 작동하지 않습니다. ‘ System.DBNull
‘ 에서 ‘ ‘로의 잘못된 캐스트 System.Guid
예외가 발생했습니다.Convert.ChangeType
변경 사항을 다음으로 수정하려면 :
var convertedValue = value == System.DBNull.Value ? null : Convert.ChangeType(value, targetType);
답변
이것은 매우 오래된 질문이지만 ASP.NET Core Google 직원을 위해 차임 할 것이라고 생각했습니다.
ASP.NET Core에서는 .IsNullableType()
다른 변경 사항과 함께 보호되므로 코드가 약간 다릅니다. 다음은 ASP.NET Core에서 작동하도록 수정 된 @jeroenh의 답변입니다.
void SetValue(PropertyInfo info, object instance, object value)
{
Type proptype = info.PropertyType;
if (proptype.IsGenericType && proptype.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
proptype = new NullableConverter(info.PropertyType).UnderlyingType;
}
var convertedValue = Convert.ChangeType(value, proptype);
info.SetValue(instance, convertedValue);
}