ibo*_*eno 288 .net c# reflection
我想将一个字符串转换为一个对象属性值,其名称我作为一个字符串.我试图这样做:
string modelProperty = "Some Property Name";
string value = "SomeValue";
var property = entity.GetType().GetProperty(modelProperty);
if (property != null) {
property.SetValue(entity,
Convert.ChangeType(value, property.PropertyType), null);
}
Run Code Online (Sandbox Code Playgroud)
问题是,当属性类型为可空类型时,这会失败并抛出Invalid Cast Exception.这不是无法转换的值的情况 - 如果我手动执行此操作它们将起作用(例如DateTime? d = Convert.ToDateTime(value);)我已经看到了一些类似的问题,但仍然无法使其工作.
Luk*_*keH 390
未经测试,但也许这样的事情会起作用:
string modelProperty = "Some Property Name";
string value = "Some Value";
var property = entity.GetType().GetProperty(modelProperty);
if (property != null)
{
Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
object safeValue = (value == null) ? null : Convert.ChangeType(value, t);
property.SetValue(entity, safeValue, null);
}
Run Code Online (Sandbox Code Playgroud)
Ben*_*ter 72
你必须得到基础类型才能做到这一点......
试试这个,我已经成功地使用了泛型:
//Coalesce to get actual property type...
Type t = property.PropertyType();
t = Nullable.GetUnderlyingType(t) ?? t;
//Coalesce to set the safe value using default(t) or the safe type.
safeValue = value == null ? default(t) : Convert.ChangeType(value, t);
Run Code Online (Sandbox Code Playgroud)
我在我的代码中的许多地方使用它,一个例子是我用于以类型安全的方式转换数据库值的辅助方法:
public static T GetValue<T>(this IDataReader dr, string fieldName)
{
object value = dr[fieldName];
Type t = typeof(T);
t = Nullable.GetUnderlyingType(t) ?? t;
return (value == null || DBNull.Value.Equals(value)) ?
default(T) : (T)Convert.ChangeType(value, t);
}
Run Code Online (Sandbox Code Playgroud)
叫做使用:
string field1 = dr.GetValue<string>("field1");
int? field2 = dr.GetValue<int?>("field2");
DateTime field3 = dr.GetValue<DateTime>("field3");
Run Code Online (Sandbox Code Playgroud)
我在http://www.endswithsaurus.com/2010_07_01_archive.html写了一系列博客文章(向下滚动到附录,@ JohnMacintyre实际上发现了我原始代码中的错误,这导致我走的路径与你相同现在).我发布了一些小修改,包括枚举类型的转换,所以如果你的属性是枚举,你仍然可以使用相同的方法调用.只需添加一行以检查枚举类型,您就可以使用以下内容进行比赛:
if (t.IsEnum)
return (T)Enum.Parse(t, value);
Run Code Online (Sandbox Code Playgroud)
通常你会有一些错误检查或使用TryParse而不是Parse,但你得到了图片.
Maj*_*jor 12
即使对于可为 Null 的类型,这也非常有效:
TypeConverter conv = TypeDescriptor.GetConverter(type);
return conv.ConvertFrom(value);
Run Code Online (Sandbox Code Playgroud)
为了类型安全,您还应该conv.CanConvertFrom(type)在调用之前调用方法ConvertFrom()。如果它返回 false,您可以回退到ChangeType其他内容。
这是一个有点长的例子,但这是一个相对强大的方法,并将铸造的任务从未知值分离到未知类型
我有一个类似的TryCast方法,并考虑可以为空的类型.
public static bool TryCast<T>(this object value, out T result)
{
var type = typeof (T);
// If the type is nullable and the result should be null, set a null value.
if (type.IsNullable() && (value == null || value == DBNull.Value))
{
result = default(T);
return true;
}
// Convert.ChangeType fails on Nullable<T> types. We want to try to cast to the underlying type anyway.
var underlyingType = Nullable.GetUnderlyingType(type) ?? type;
try
{
// Just one edge case you might want to handle.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
当然,TryCast是一个带有类型参数的方法,因此要动态调用它,您必须自己构造MethodInfo:
var constructedMethod = typeof (ObjectExtensions)
.GetMethod("TryCast")
.MakeGenericMethod(property.PropertyType);
Run Code Online (Sandbox Code Playgroud)
然后设置实际属性值:
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);
}
Run Code Online (Sandbox Code Playgroud)
以及处理property.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;
}
Run Code Online (Sandbox Code Playgroud)
我有类似的需求,LukeH的答案指出了我的方向.我想出了这个通用功能,让它变得简单.
public static Tout CopyValue<Tin, Tout>(Tin from, Tout toPrototype)
{
Type underlyingT = Nullable.GetUnderlyingType(typeof(Tout));
if (underlyingT == null)
{ return (Tout)Convert.ChangeType(from, typeof(Tout)); }
else
{ return (Tout)Convert.ChangeType(from, underlyingT); }
}
Run Code Online (Sandbox Code Playgroud)
用法是这样的:
NotNullableDateProperty = CopyValue(NullableDateProperty, NotNullableDateProperty);
Run Code Online (Sandbox Code Playgroud)
请注意,第二个参数仅用作原型来显示如何转换返回值的函数,因此它实际上不必是目标属性.意思是你也可以这样做:
DateTime? source = new DateTime(2015, 1, 1);
var dest = CopyValue(source, (string)null);
Run Code Online (Sandbox Code Playgroud)
我这样做而不是使用out,因为你不能使用属性.它可以使用属性和变量.如果需要,您还可以创建一个重载来传递类型.