C# 使用反射设置对象属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/619767/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Set object property using reflection
提问by Melursus
Is there a way in C# where I can use reflection to set an object property?
在 C# 中有没有一种方法可以使用反射来设置对象属性?
Ex:
前任:
MyObject obj = new MyObject();
obj.Name = "Value";
I want to set obj.Name
with reflection. Something like:
我想设置obj.Name
反射。就像是:
Reflection.SetProperty(obj, "Name") = "Value";
Is there a way of doing this?
有没有办法做到这一点?
采纳答案by Andy
Yes, you can use Type.InvokeMember()
:
是的,您可以使用Type.InvokeMember()
:
using System.Reflection;
MyObject obj = new MyObject();
obj.GetType().InvokeMember("Name",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, obj, "Value");
This will throw an exception if obj
doesn't have a property called Name
, or it can't be set.
如果obj
没有名为 的属性Name
,或者无法设置,这将引发异常。
Another approach is to get the metadata for the property, and then set it. This will allow you to check for the existence of the property, and verify that it can be set:
另一种方法是获取属性的元数据,然后设置它。这将允许您检查属性是否存在,并验证它是否可以设置:
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);
}
回答by El Cheicon
You can also do:
你也可以这样做:
Type type = target.GetType();
PropertyInfo prop = type.GetProperty("propertyName");
prop.SetValue (target, propertyValue, null);
where target is the object that will have its property set.
其中 target 是将设置其属性的对象。
回答by JoshBerke
You can also access fields using a simillar manner:
您还可以使用类似的方式访问字段:
var obj=new MyObject();
FieldInfo fi = obj.GetType().
GetField("Name", BindingFlags.NonPublic | BindingFlags.Instance);
fi.SetValue(obj,value)
With reflection everything can be an open book:) In my example we are binding to a private instance level field.
通过反射,一切都可以是一本打开的书:) 在我的示例中,我们绑定到一个私有实例级别的字段。
回答by Marc Gravell
Reflection, basically, i.e.
反射,基本上,即
myObject.GetType().GetProperty(property).SetValue(myObject, "Bob", null);
or there are libraries to help both in terms of convenience and performance; for example with FastMember:
或者有一些库可以在便利性和性能方面提供帮助;例如使用FastMember:
var wrapped = ObjectAccessor.Create(obj);
wrapped[property] = "Bob";
(which also has the advantage of not needing to know in advance whether it is a field vs a property)
(这还有一个好处就是不需要提前知道是field还是property)
回答by D Stanley
Yes, using System.Reflection
:
是的,使用System.Reflection
:
using System.Reflection;
...
string prop = "name";
PropertyInfo pi = myObject.GetType().GetProperty(prop);
pi.SetValue(myObject, "Bob", null);
回答by Erik K.
Or you could wrap Marc's one liner inside your own extension class:
或者您可以将 Marc 的一个班轮包装在您自己的扩展类中:
public static class PropertyExtension{
public static void SetPropertyValue(this object obj, string propName, object value)
{
obj.GetType().GetProperty(propName).SetValue(obj, value, null);
}
}
and call it like this:
并这样称呼它:
myObject.SetPropertyValue("myProperty", "myValue");
For good measure, let's add a method to get a property value:
为了更好地衡量,让我们添加一个方法来获取属性值:
public static object GetPropertyValue(this object obj, string propName)
{
return obj.GetType().GetProperty(propName).GetValue (obj, null);
}
回答by user3679106
You can try this out when you want to mass-assign properties of an Object from another Object using Property names:
当您想使用属性名称从另一个对象批量分配一个对象的属性时,您可以试试这个:
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;
}
}
}
}
回答by Ardalan Shahgholi
Use somethings like this :
使用这样的东西:
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);
}
}
or
或者
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);
}
}
回答by Dogu Arslan
I have just published a Nuget package that allows setting up not only the first level Properties but also nested properties in the given object in any depth.
我刚刚发布了一个 Nuget 包,它不仅允许设置第一级属性,还允许设置给定对象中任何深度的嵌套属性。
Here is the package
这是包
Sets the value of a property of an object by its path from the root.
通过从根开始的路径设置对象的属性值。
The object can be a complex object and the property can be multi level deep nested property or it can be a property directly under the root. ObjectWriter
will find the property using the property path parameter and update its value. Property path is the appended names of the properties visited from root to the end node property which we want to set, delimited by the delimiter string parameter.
对象可以是复杂的对象,属性可以是多级深度嵌套的属性,也可以是直接在根下的属性。ObjectWriter
将使用属性路径参数查找属性并更新其值。属性路径是从根访问的属性的附加名称到我们要设置的结束节点属性,由分隔符字符串参数分隔。
Usage:
用法:
For setting up the properties directly under the object root:
直接在对象根下设置属性:
Ie. LineItem
class has an int property called ItemId
IE。LineItem
类有一个名为的 int 属性ItemId
LineItem lineItem = new LineItem();
ObjectWriter.Set(lineItem, "ItemId", 13, delimiter: null);
For setting up nested property multiple levels below the object root:
用于在对象根下设置多个级别的嵌套属性:
Ie. Invite
class has a property called State
, which has a property called Invite
(of Invite type), which has a property called Recipient
, which has a property called Id
.
IE。Invite
类有一个名为 的属性State
,该属性有一个名为Invite
(邀请类型)的属性Recipient
,该属性有一个名为 的属性,该属性有一个名为 的属性Id
。
To make things even more complex, the State
property is not a reference type, it is a struct
.
更复杂的State
是,该属性不是引用类型,而是一个struct
.
Here is how you can set the Id property (to string value of “outlook”) at the bottom of the object tree in a single line.
以下是如何在一行中设置对象树底部的 Id 属性(为“outlook”的字符串值)。
Invite invite = new Invite();
ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "outlook", delimiter: "_");
回答by Cogent
Based on MarcGravell's suggestion, I have constructed the following static method.The method genericallyassigns all matching properties from source object to target using FastMember
基于 MarcGravell 的建议,我构建了以下静态方法。该方法一般使用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);
}
}
}