c# - 如何遍历类字段并设置属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/721441/
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
c# - How to iterate through classes fields and set properties
提问by Petras
I am not sure if this is possible but I want to iterate through a class and set a field member property without referring to the field object explicitly:
我不确定这是否可行,但我想遍历一个类并设置一个字段成员属性而不显式引用字段对象:
public class Employee
{
public Person _person = new Person();
public void DynamicallySetPersonProperty()
{
MemberInfo[] members = this.GetType().GetMembers();
foreach (MemberInfo member in members.Where(a => a.Name == "_person"))
//get the _person field
{
Type type = member.GetType();
PropertyInfo prop = type.GetProperty("Name"); //good, this works, now to set a value for it
//this line does not work - the error is "property set method not found"
prop.SetValue(member, "new name", null);
}
}
}
public class Person
{
public string Name { get; set; }
}
In the answer that I marked as the answer you need to add:
在我标记为答案的答案中,您需要添加:
public static bool IsNullOrEmpty(this string source)
{
return (source == null || source.Length > 0) ? true : false;
}
采纳答案by Konstantin Tarkus
public class Person
{
public string Name { get; set; }
}
public class Employee
{
public Person person = new Person();
public void DynamicallySetPersonProperty()
{
var p = GetType().GetField("person").GetValue(this);
p.GetType().GetProperty("Name").SetValue(p, "new name", null);
}
}
回答by Chris Ballance
Have a look on this CodeProject article related to what you are trying to do
看看这篇与你正在尝试做的事情相关的 CodeProject 文章
http://www.codeproject.com/KB/cs/fast_dynamic_properties.aspx
http://www.codeproject.com/KB/cs/fast_dynamic_properties.aspx
回答by David M
You are trying to set the Name property of your Employee class's _person field. It doesn't have one. Try this:
您正在尝试设置 Employee 类的 _person 字段的 Name 属性。它没有。尝试这个:
prop.SetValue(((FieldInfo)member).GetValue(this), "new name", null)
Not sure if you need to cast the first argument like this:
不确定是否需要像这样转换第一个参数:
prop.SetValue((Person)((FieldInfo)member).GetValue(this), "new name", null)
This then applies it to the value of the _person field instead.
然后将其应用于 _person 字段的值。
回答by Daniel Brückner
You a trying to perform SetValue()on the property Nameof the variable memberthat is a MemberInfo object and this proeprty is read only.
您尝试对作为 MemberInfo 对象的变量SetValue()的属性执行操作,并且此属性是只读的。Namemember
Note you do not need to iterate over all memebers and you do not need to get the field _personwith reflection as it is defined in the same class as the method DynamicallySetPersonProperty().
请注意,您不需要遍历所有成员,也不需要_person使用反射获取字段,因为它与方法在同一类中定义DynamicallySetPersonProperty()。
So the code shoul read like this.
所以代码应该是这样的。
PropertyInfo property = this._person.GetType().GetProperty("Name");
property.SetValue(this._person, "new name", null);
The first line will fail if _personis null. So you can use reflectiopn to get the type of the field.
如果_person为空,第一行将失败。所以你可以使用reflectionpn来获取字段的类型。
FieldInfo field = this.GetType().GetField("_person", BindingFlags.Public);
PropertyInfo property = field.FieldType.GetProperty("Name");
But now accessing this property will still fail if _personis null.
但是现在如果_person为空,访问这个属性仍然会失败。
property.Setvalue(field.GetValue(this), "new name", null);
回答by plinth
Here's a complete working example:
这是一个完整的工作示例:
public class Person
{
public string Name { get; set; }
}
class Program
{
static void PropertySet(object p, string propName, object value)
{
Type t = p.GetType();
PropertyInfo info = t.GetProperty(propName);
if (info == null)
return;
if (!info.CanWrite)
return;
info.SetValue(p, value, null);
}
static void PropertySetLooping(object p, string propName, object value)
{
Type t = p.GetType();
foreach (PropertyInfo info in t.GetProperties())
{
if (info.Name == propName && info.CanWrite)
{
info.SetValue(p, value, null);
}
}
}
static void Main(string[] args)
{
Person p = new Person();
PropertySet(p, "Name", "Michael Ellis");
Console.WriteLine(p.Name);
PropertySetLooping(p, "Name", "Nigel Mellish");
Console.WriteLine(p.Name);
}
}
EDIT: added a looping variant so you could see how to loop through property info objects.
编辑:添加了一个循环变体,以便您可以了解如何循环访问属性信息对象。
回答by Paleta
With the following Extension methods that I have created, you can set or get any property value even if they are nested
使用我创建的以下扩展方法,您可以设置或获取任何属性值,即使它们是嵌套的
GetPropertyValue(customObject, "Property.Nested.Child.Name");
GetPropertyValue(customObject, "Property.Nested.Child.Name");
or set
或设置
SetPropertyValue(customObject, "Property.Nested.Child.Name", "my custom name");
SetPropertyValue(customObject, "Property.Nested.Child.Name", "我的自定义名称");
private class TargetProperty
{
public object Target { get; set; }
public PropertyInfo Property { get; set; }
public bool IsValid { get { return Target != null && Property != null; } }
}
private static TargetProperty GetTargetProperty(object source, string propertyName)
{
if (!propertyName.Contains("."))
return new TargetProperty { Target = source, Property = source.GetType().GetProperty(propertyName) };
string[] propertyPath = propertyName.Split('.');
var targetProperty = new TargetProperty();
targetProperty.Target = source;
targetProperty.Property = source.GetType().GetProperty(propertyPath[0]);
for (int propertyIndex = 1; propertyIndex < propertyPath.Length; propertyIndex++)
{
propertyName = propertyPath[propertyIndex];
if (!string.IsNullOrEmpty(propertyName))
{
targetProperty.Target = targetProperty.Property.GetValue(targetProperty.Target, null);
targetProperty.Property = targetProperty.Target.GetType().GetProperty(propertyName);
}
}
return targetProperty;
}
public static bool HasProperty(this object source, string propertyName)
{
return GetTargetProperty(source, propertyName).Property != null;
}
public static object GetPropertyValue(this object source, string propertyName)
{
var targetProperty = GetTargetProperty(source, propertyName);
if (targetProperty.IsValid)
{
return targetProperty.Property.GetValue(targetProperty.Target, null);
}
return null;
}
public static void SetPropertyValue(this object source, string propertyName, object value)
{
var targetProperty = GetTargetProperty(source, propertyName);
if(targetProperty.IsValid)
{
targetProperty.Property.SetValue(targetProperty.Target, value, null);
}
}
And here are a couple of tests for it
这里有几个测试
[TestFixture]
public class ObjectExtensionsTest
{
private class MockClass
{
public MockClass()
{
Nested = new NestedMockClass();
}
public string Id { get; set; }
public string Name { get; set; }
public string GetOnly { get { return "MockClass"; } }
public string SetOnly { set { } }
public NestedMockClass Nested { get; set; }
}
private class NestedMockClass
{
public string NestedId { get; set; }
public string NestedName { get; set; }
public string NestedGetOnly { get { return "NestedMockClass"; } }
public string NestedSetOnly { set { } }
}
[Test]
public void TestShouldFindProperty()
{
MockClass mockObject = new MockClass();
Assert.IsTrue(mockObject.HasProperty("Id"));
Assert.IsTrue(mockObject.HasProperty("Name"));
Assert.IsTrue(mockObject.HasProperty("GetOnly"));
Assert.IsTrue(mockObject.HasProperty("SetOnly"));
Assert.IsTrue(mockObject.HasProperty("Nested"));
Assert.IsTrue(mockObject.HasProperty("Nested.NestedId"));
Assert.IsTrue(mockObject.HasProperty("Nested.NestedName"));
Assert.IsTrue(mockObject.HasProperty("Nested.NestedGetOnly"));
Assert.IsTrue(mockObject.HasProperty("Nested.NestedSetOnly"));
}
[Test]
public void TestShouldGetPropertyValue()
{
MockClass mockObject = new MockClass();
mockObject.Id = "1";
mockObject.Name = "Name";
mockObject.Nested.NestedId = "NestedId";
mockObject.Nested.NestedName = "NestedName";
Assert.AreEqual(mockObject.Id, mockObject.GetPropertyValue("Id"));
Assert.AreEqual(mockObject.Name, mockObject.GetPropertyValue("Name"));
Assert.AreEqual(mockObject.GetOnly, mockObject.GetPropertyValue("GetOnly"));
Assert.AreEqual(mockObject.Nested.NestedId, mockObject.GetPropertyValue("Nested.NestedId"));
Assert.AreEqual(mockObject.Nested.NestedName, mockObject.GetPropertyValue("Nested.NestedName"));
}
[Test]
public void TestShouldSetPropertyValue()
{
MockClass mockObject = new MockClass();
mockObject.SetPropertyValue("Id", "1");
mockObject.SetPropertyValue("Name", "Name");
mockObject.SetPropertyValue("Nested.NestedId", "NestedId");
mockObject.SetPropertyValue("Nested.NestedName", "NestedName");
Assert.AreEqual(mockObject.Id, "1");
Assert.AreEqual(mockObject.Name, "Name");
Assert.AreEqual(mockObject.Nested.NestedId, "NestedId");
Assert.AreEqual(mockObject.Nested.NestedName, "NestedName");
}
}
Hope you find it useful.
希望你觉得它有用。
回答by Paleta
try this:
尝试这个:
public static void ApplyPropertyChanges(this object objDest, object objToCopyFrom)
{
if (objDest == null)
throw new ArgumentNullException();
if (objToCopyFrom == null)
throw new ArgumentNullException("objToCopyFrom");
if (objDest.GetType() != objToCopyFrom.GetType())
throw new Exception("Invalid type. Required: \"" + objDest.GetType().ToString() + "\"");
foreach (System.Reflection.PropertyInfo piOrig in objDest.GetType().GetProperties())
{
object editedVal = objToCopyFrom.GetType().GetProperty(piOrig.Name).GetValue(objToCopyFrom, null);
piOrig.SetValue(objDest,
editedVal,
null);
}
}
usage example:
用法示例:
public ActionResult Edit(Team editedTeamData)
{
if (!ModelState.IsValid)
return View();
Team origTeam = (from t in _db.Teams
where t.TeamID == editedTeamData.TeamID
select t).FirstOrDefault();
origTeam.ApplyPropertyChanges(editedTeamData);
_db.SubmitChanges();
return RedirectToAction("Index");
}

