反射调用列表中类中的方法

本文关键字:方法 反射 列表 调用 | 更新日期: 2023-09-27 18:16:15

我有一个类与一些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;
}

我的建议是更安全的重构,因为你会遇到一个编译时的错误,每次你改变CustomerName属性。

旁注:我同意Tim S.的观点。你可能会找到一种比反射更安全、更高效的方式:)。

这个例子应该让你开始:

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

现在,nameobject的一个实例,其值等于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吗?