这个示例有点长,但是这是一种相对强大的方法,可以将未知值转换为未知类型,并从中分离出了转换的任务。
我有一个TryCast方法,它也类似地考虑了可空类型。
public static bool TryCast<T>(this object value, out T result)
{
var type = typeof (T);
if (type.IsNullable() && (value == null || value == DBNull.Value))
{
result = default(T);
return true;
}
var underlyingType = Nullable.GetUnderlyingType(type) ?? type;
try
{
if (underlyingType == typeof(Guid))
{
if (value is string)
{
value = new Guid(value as string);
}
if (value is byte[])
{
value = new Guid(value as byte[]);
}
result = (T)Convert.ChangeType(value, underlyingType);
return true;
}
result = (T)Convert.ChangeType(value, underlyingType);
return true;
}
catch (Exception ex)
{
result = default(T);
return false;
}
}
当然,TryCast是一个带有类型参数的方法,因此要动态调用它,您需要自己构造MethodInfo:
var constructedMethod = typeof (ObjectExtensions)
.GetMethod("TryCast")
.MakeGenericMethod(property.PropertyType);
然后设置实际属性值:
public static void SetCastedValue<T>(this PropertyInfo property, T instance, object value)
{
if (property.DeclaringType != typeof(T))
{
throw new ArgumentException("property's declaring type must be equal to typeof(T).");
}
var constructedMethod = typeof (ObjectExtensions)
.GetMethod("TryCast")
.MakeGenericMethod(property.PropertyType);
object valueToSet = null;
var parameters = new[] {value, null};
var tryCastSucceeded = Convert.ToBoolean(constructedMethod.Invoke(null, parameters));
if (tryCastSucceeded)
{
valueToSet = parameters[1];
}
if (!property.CanAssignValue(valueToSet))
{
return;
}
property.SetValue(instance, valueToSet, null);
}
还有与属性.CanAssignValue处理相关的扩展方法...
public static bool CanAssignValue(this PropertyInfo p, object value)
{
return value == null ? p.IsNullable() : p.PropertyType.IsInstanceOfType(value);
}
public static bool IsNullable(this PropertyInfo p)
{
return p.PropertyType.IsNullable();
}
public static bool IsNullable(this Type t)
{
return !t.IsValueType || Nullable.GetUnderlyingType(t) != null;
}