我有一个类与一些setter和getter称为客户持有一些字符串值。然后我创建了一个List,并向其中添加了许多Customer类。然后我如何使用反射访问getter和setter方法?
List<Customer> Customers; // assume we have filled it
Customers[0].Name; // how do I use reflection to call this from a string?
Customer类、Customers和Name方法都是公共的。
我在一种情况下,我需要动态地获得基于列的用户试图编辑的类的值。列名是我需要调用的方法的名称。
我已经研究了GetType(). getmethod(),我的问题是如何将它与上面的列表一起使用。
更新:有一篇很好的文章解释了如何使用重构安全代码访问方法或属性,并提供了相关代码。http://www.codeducky.org/10-utilities-c-developers-should-know-part-two/
所有给出的答案都是正确的。然而,没有一个是重构安全的。我认为我应该提供一个更安全的重构解决方案。
//Create a dictionary of columnName => property info using the GetPropertyInfo method.
public static IDictionary<string, PropertyInfo> propertyInfos = new Dictionary<string, PropertyInfo>
{
{"Name", GetPropertyInfo((Customer c) => c.Name) }
};
List<Customer> Customers= new List<Customer> { new Customer { Name = "Peter Pan" } };
Customer customer = Customers[0];
string column = "Name";
PropertyInfo propertyInfo = propertyInfos[column];
//Set property
propertyInfo.SetValue(customer, "Captain Hook", null);
//Get property -- Returns Captain Hook
object propertyValue = propertyInfo.GetValue(customer, null);
我从这个答案中取了GetPropertyInfo
。我稍微修改了一下,删除了source
参数,因为你可以从HappyNomad的注释中看到,对于最新版本的c#来说,这是不必要的。
public static PropertyInfo GetPropertyInfo<TSource, TProperty>(Expression<Func<TSource, TProperty>> propertyLambda)
{
Type type = typeof(TSource);
MemberExpression member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));
PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));
if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(string.Format(
"Expresion '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));
return propInfo;
}
我的建议是更安全的重构,因为你会遇到一个编译时的错误,每次你改变Customer
的Name
属性。
旁注:我同意Tim S.的观点。你可能会找到一种比反射更安全、更高效的方式:)。
这个例子应该让你开始:
var namePropertyInfo = typeof(Customer).GetProperty("Name");
var name = namePropertyInfo.GetValue(Customers[0], null);
现在,name
是object
的一个实例,其值等于Customer[0].Name
。相应地进行。
这取决于你问题的"动态"部分从哪里开始。是否需要动态访问List本身?如果是这样,那么您有两个动态(反射)调用要进行。但是,如果您可以直接访问List,并且可以使用索引器找到正确的客户,并且只有然后需要使用反射调用,那么您的代码将看起来像:
var fieldName = "Name";
var customer = Customers[x];
Type type = typeof(Customer);
var prop = type.GetProperties().Single(field => field.Name == fieldName);
// once you have your propinfo + your reference to the right customer, just call...
Object value = prop.GetValue(customer, null); // you'll need to cast/convert away from object
查看LINQ中使用PropertyInfo对象查询集合
这就是你所问的问题的答案:
void Main()
{
List<Customer> Customers= new List<Customer> { new Customer { Name = "John Smith" } };
GetProp(Customers[0], "Name"); // "John Smith"
SetProp(Customers[0], "Name", "Joe");
GetProp(Customers[0], "Name"); // "Joe"
}
object GetProp(Customer customer, string propertyName)
{
var property = typeof(Customer).GetProperty(propertyName);
return property.GetValue(customer);
}
void SetProp(Customer customer, string propertyName, object propertyValue)
{
var property = typeof(Customer).GetProperty(propertyName);
property.SetValue(customer, propertyValue);
}
或者处理非强类型列表:
void Main()
{
List<Customer> Customers= new List<Customer> { new Customer { Name = "John Smith" } };
string name = (string)GetProp(Customers, 0, "Name"); // name == "John Smith"
}
object GetProp(object customerList, int index, string propertyName)
{
var custList = (IList)customerList;
var customer = custList[index];
var nameProperty = customer.GetType().GetProperty(propertyName);
return nameProperty.GetValue(customer);
}
这是我认为你应该真正做的:不要使用反射作为修改表/网格值的一部分,而不是基于列名(显示值和属性名并不总是相同的)。你应该怎么做?这取决于您使用的是什么框架:WPF?ASP。. NET网站?WinForms吗?