使用反射给实例的属性赋值
我们经常有这样的需求,就是我们需要使用属性名来给属性赋值,而不能直接使用类似obj.prop = value
这种方式。
比如我们有有一个Dictionary
,key是属性名,value是属性值。我们需要把它们变成一个对象,就可以使用这种方式。
这里我们的代码可以这样写:
public static void SetProperty(object obj, string name, object value, BindingFlags bindingFlags = BindingFlags.Public)
{
var t = obj.GetType();
var p = t.GetProperty(name, bindingFlags);
if (p == null)
{
throw new InvalidOperationException($"未找到 {name} 属性");
}
if (!p.PropertyType.IsGenericType)
{
p.SetValue(obj, Convert.ChangeType(value, p.PropertyType));
}
else
{
var genericTypeDefinition = p.PropertyType.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(Nullable<>))
{
p.SetValue(obj,
Convert.ChangeType(value,
Nullable.GetUnderlyingType(p.PropertyType) ??
throw new InvalidOperationException("获取类型失败")));
}
else
{
throw new InvalidOperationException("只能对基础类型进行赋值");
}
}
}
这里注意几个问题,就是首先我们获取Property
的时候是可以处理BindingFlags
的,如果我们还需要处理私有属性或者静态属性,这里可以修改BindingFlags
。
这种p.SetValue
的方法不能给泛型类型赋值,所以这里就只能判断一下p.PropertyType.IsGenericType
,看是否为泛型类型。
但是泛型类型中有一个特例,就是Nullable
,这玩意是个啥呢,就是int?
这种可空类型。
可空类型是可以给他进行赋值的,所以我们这里判断一下是否为可空类型。genericTypeDefinition == typeof(Nullable<>)
,如果是可空类型的话就使用Nullable.GetUnderlyingType
获取其真实类型转换后赋值。
最后我们还可以把它做成object
的扩展,直接在任意对象上都可以使用,这就是我的jx.toolbox中的做法了。