使用reflection设置对象属性

在C#3.5中有一种方法可以使用reflection设置对象属性吗?

例如:

MyObject obj = new MyObject(); obj.Name = "Value"; 

我想用reflection来设置obj.Name 。 就像是:

 Reflection.SetProperty(obj, "Name") = "Value"; 

有没有办法做到这一点?

是的,你可以使用Type.InvokeMember()

 using System.Reflection; MyObject obj = new MyObject(); obj.GetType().InvokeMember("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty, Type.DefaultBinder, obj, "Value"); 

如果obj没有名为Name的属性,则会抛出exception,或者无法设置。

另一种方法是获取属性的元数据,然后进行设置。 这将允许您检查财产的存在,并validation它可以设置:

 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); } 

你也可以这样做:

 Type type = target.GetType(); PropertyInfo prop = type.GetProperty("propertyName"); prop.SetValue (target, propertyValue, null); 

其中target是将要设置其属性的对象。

反思,基本上,即

 myObject.GetType().GetProperty(property).SetValue(myObject, "Bob", null); 

或者有便利和性能方面的帮助; 例如使用FastMember :

 var wrapped = ObjectAccessor.Create(obj); wrapped[property] = "Bob"; 

(这也有不需要事先知道是场还是场的优势)

或者你可以在你自己的扩展类中包装Marc的一个class轮:

 public static class PropertyExtension{ public static void SetPropertyValue(this object obj, string propName, object value) { obj.GetType().GetProperty(propName).SetValue(obj, value, null); } } 

并像这样调用它:

 myObject.SetPropertyValue("myProperty", "myValue"); 

为了好的措施,让我们添加一个方法来获取属性值:

 public static object GetPropertyValue(this object obj, string propName) { return obj.GetType().GetProperty(propName).GetValue (obj, null); } 

是的,使用System.Reflection

 using System.Reflection; ... string prop = "name"; PropertyInfo pi = myObject.GetType().GetProperty(prop); pi.SetValue(myObject, "Bob", null); 

您也可以使用一种同样的方式访问字段:

 var obj=new MyObject(); FieldInfo fi = obj.GetType(). GetField("Name", BindingFlags.NonPublic | BindingFlags.Instance); fi.SetValue(obj,value) 

随着反思一切都可以是一本开放的书:)在我的例子中,我们绑定到一个私人实例级别字段。

使用这样的东西:

 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); } } 

要么

 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); } } 

当你想使用属性名称从另一个对象来批量分配一个对象的属性时,你可以试试这个:

 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; } } } } 

我刚刚发布了一个Nuget包,它不仅可以设置第一层的属性,还可以在给定的对象中设置嵌套的属性。

这是包

通过根目录的path设置对象属性的值。

该对象可以是一个复杂的对象,属性可以是多级深嵌套属性,也可以是直接在根下的属性。 ObjectWriter将使用属性path参数查找属性并更新其值。 属性path是从根到我们要设置的结束节点属性访问的属性的附加名称,由定界符string参数定界。

用法:

为了直接在对象根目录下设置属性:

IE浏览器。 LineItem类有一个名为ItemId的int属性

 LineItem lineItem = new LineItem(); ObjectWriter.Set(lineItem, "ItemId", 13, delimiter: null); 

为了在对象根下设置嵌套属性多个级别:

IE浏览器。 Invite类具有一个名为State的属性,该属性具有名为Invite (属于Invitetypes)的属性,该属性具有名为Recipient的属性,该属性具有称为Id的属性。

为了使事情更加复杂, State属性不是一个引用types,它是一个struct

以下是如何在一行中设置对象树底部的Id属性(string值为“outlook”)。

 Invite invite = new Invite(); ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "outlook", delimiter: "_"); 

基于MarcGravell的build议,我已经构build了以下静态方法。该方法通常使用FastMember将所有从源对象到目标的匹配属性

  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); } } }