Set object property using reflection
在C中有没有一种方法可以使用反射来设置对象属性?
前任:
1 2 |
我想让
1 | Reflection.SetProperty(obj,"Name") ="Value"; |
有办法做到这一点吗?
是的,您可以使用
1 2 3 4 5 | using System.Reflection; MyObject obj = new MyObject(); obj.GetType().InvokeMember("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty, Type.DefaultBinder, obj,"Value"); |
如果
另一种方法是获取属性的元数据,然后对其进行设置。这将允许您检查属性是否存在,并验证是否可以设置:
1 2 3 4 5 6 7 | using System.Reflection; MyObject obj = new MyObject(); PropertyInfo prop = obj.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance); if(null != prop && prop.CanWrite) { prop.SetValue(obj,"Value", null); } |
您还可以执行以下操作:
1 2 3 4 5 | Type type = target.GetType(); PropertyInfo prop = type.GetProperty("propertyName"); prop.SetValue (target, propertyValue, null); |
其中,target是将设置其属性的对象。
反射,基本上,即
1 | myObject.GetType().GetProperty(property).SetValue(myObject,"Bob", null); |
或者有一些库可以在方便性和性能方面提供帮助;例如,对于fastmember:
1 2 | var wrapped = ObjectAccessor.Create(obj); wrapped[property] ="Bob"; |
(其优点是不需要事先知道它是字段还是属性)
或者你可以把Marc的一行包装在你自己的扩展类中:
1 2 3 4 5 6 7 | public static class PropertyExtension{ public static void SetPropertyValue(this object obj, string propName, object value) { obj.GetType().GetProperty(propName).SetValue(obj, value, null); } } |
这样称呼它:
1 | myObject.SetPropertyValue("myProperty","myValue"); |
为了更好地度量,我们添加一个方法来获取属性值:
1 2 3 4 | public static object GetPropertyValue(this object obj, string propName) { return obj.GetType().GetProperty(propName).GetValue (obj, null); } |
是的,使用
1 2 3 4 5 6 7 | using System.Reflection; ... string prop ="name"; PropertyInfo pi = myObject.GetType().GetProperty(prop); pi.SetValue(myObject,"Bob", null); |
您还可以使用类似的方式访问字段:
1 2 3 4 | var obj=new MyObject(); FieldInfo fi = obj.GetType(). GetField("Name", BindingFlags.NonPublic | BindingFlags.Instance); fi.SetValue(obj,value) |
通过反射,一切都可以是一本开放的书:)在我的示例中,我们绑定到一个私有实例级字段。
使用这样的东西:
1 2 3 4 5 6 7 8 | public static class PropertyExtension{ public static void SetPropertyValue(this object p_object, string p_propertyName, object value) { PropertyInfo property = p_object.GetType().GetProperty(p_propertyName); property.SetValue(p_object, Convert.ChangeType(value, property.PropertyType), null); } } |
或
1 2 3 4 5 6 7 8 9 10 11 | public static class PropertyExtension{ public static void SetPropertyValue(this object p_object, string p_propertyName, object value) { PropertyInfo property = p_object.GetType().GetProperty(p_propertyName); Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; object safeValue = (value == null) ? null : Convert.ChangeType(value, t); property.SetValue(p_object, safeValue, null); } } |
如果要使用属性名称从其他对象批量分配对象的属性,可以尝试此操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public static void Assign(this object destination, object source) { if (destination is IEnumerable && source is IEnumerable) { var dest_enumerator = (destination as IEnumerable).GetEnumerator(); var src_enumerator = (source as IEnumerable).GetEnumerator(); while (dest_enumerator.MoveNext() && src_enumerator.MoveNext()) dest_enumerator.Current.Assign(src_enumerator.Current); } else { var destProperties = destination.GetType().GetProperties(); foreach (var sourceProperty in source.GetType().GetProperties()) { foreach (var destProperty in destProperties) { if (destProperty.Name == sourceProperty.Name && destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType)) { destProperty.SetValue(destination, sourceProperty.GetValue(source, new object[] { }), new object[] { }); break; } } } } |
根据MarcGravell的建议,我构造了以下静态方法,该方法使用fastmember将源对象到目标的所有匹配属性一般地分配给目标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | public static void DynamicPropertySet(object source, object target) { //SOURCE var src_accessor = TypeAccessor.Create(source.GetType()); if (src_accessor == null) { throw new ApplicationException("Could not create accessor!"); } var src_members = src_accessor.GetMembers(); if (src_members == null) { throw new ApplicationException("Could not fetch members!"); } var src_class_members = src_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive); var src_class_propNames = src_class_members.Select(x => x.Name); var src_propNames = src_members.Except(src_class_members).Select(x => x.Name); //TARGET var trg_accessor = TypeAccessor.Create(target.GetType()); if (trg_accessor == null) { throw new ApplicationException("Could not create accessor!"); } var trg_members = trg_accessor.GetMembers(); if (trg_members == null) { throw new ApplicationException("Could not create accessor!"); } var trg_class_members = trg_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive); var trg_class_propNames = trg_class_members.Select(x => x.Name); var trg_propNames = trg_members.Except(trg_class_members).Select(x => x.Name); var class_propNames = trg_class_propNames.Intersect(src_class_propNames); var propNames = trg_propNames.Intersect(src_propNames); foreach (var propName in propNames) { trg_accessor[target, propName] = src_accessor[source, propName]; } foreach (var member in class_propNames) { var src = src_accessor[source, member]; var trg = trg_accessor[target, member]; if (src != null && trg != null) { DynamicPropertySet(src, trg); } } } |
我刚刚发布了一个nuget包,它不仅允许在给定对象中设置一级属性,还允许在任何深度设置嵌套属性。
这是包裹
按对象从根目录的路径设置其属性的值。
对象可以是复杂的对象,属性可以是多级深度嵌套属性,也可以是直接在根下的属性。
用途:
要直接在对象根目录下设置属性,请执行以下操作:
即,
1 2 3 |
用于在对象根目录下设置多个级别的嵌套属性:
也就是说,
更复杂的是,
下面是如何在对象树底部的一行中设置id属性(设置为字符串值"outlook")。
1 2 3 | Invite invite = new Invite(); ObjectWriter.Set(invite,"State_Invite_Recipient_Id","outlook", delimiter:"_"); |