3

我有一个包含一些 setter 和 getter 的类,称为 Customer,它包含一些字符串值。然后我创建一个 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() ,我的问题是如何将它与上面的列表一起使用。

一个例子可以解决我的问题。

4

4 回答 4

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

我取自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.。您可能会找到比反射更安全、更高效的方法:)。

于 2013-06-01T14:41:42.463 回答
1

这取决于问题的“动态”部分从哪里开始。您是否需要动态访问列表本身?如果是这样,那么您需要进行两个动态(反射)调用。但是,如果您可以直接访问 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 对象查询集合

于 2013-06-01T13:25:57.077 回答
1

这个例子应该让你开始:

var namePropertyInfo = typeof(Customer).GetProperty("Name");
var name = namePropertyInfo.GetValue(Customers[0], null);

现在,name是 的一个实例,object其值等于Customer[0].Name。相应地进行。

于 2013-06-01T13:40:02.300 回答
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 网站?表格?

于 2013-06-01T14:00:02.920 回答