我有一个类,其中包含一些名为Customer的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(),我的问题是如何将它与我上面的列表一起使用。
一个例子可以解决我的问题。
答案 0 :(得分:2)
更新:有一篇很好的文章解释了如何使用重构安全代码访问方法或属性的代码。 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);
我从this answer开始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;
}
我的建议是更加重构安全,因为每次更改Name
上的Customer
属性时都会遇到编译时错误。
旁注:我同意 Tim S。。你可能会找到比反射更安全,更高效的方式:)。
答案 1 :(得分:1)
这取决于问题的“动态”部分的开始位置。您是否需要动态访问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
有关详细信息,请参阅Query a collection using PropertyInfo object in LINQ
答案 2 :(得分:1)
这个例子应该让你开始:
var namePropertyInfo = typeof(Customer).GetProperty("Name");
var name = namePropertyInfo.GetValue(Customers[0], null);
现在,name
是object
的一个实例,其值等于Customer[0].Name
。继续相应。
答案 3 :(得分:1)
以下是您要问的答案:
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?