C#使用反射获取通用对象(及其嵌套对象)属性

时间:2010-05-26 09:39:51

标签: c# generics reflection properties types

这是为了帮助理解我想要实现的目标而创建的场景。

我正在尝试创建一个返回泛型对象的指定属性的方法

e.g。

public object getValue<TModel>(TModel item, string propertyName) where TModel : class{
    PropertyInfo p = typeof(TModel).GetProperty(propertyName);
    return p.GetValue(item, null);
}

如果您在TModel item上寻找属性,上面的代码就可以正常运行 例如

string customerName = getValue<Customer>(customer, "name");

但是,如果您想了解客户群组的名称,则会出现问题: 例如

string customerGroupName = getValue<Customer>(customer, "Group.name");

希望有人能给我一些关于这种情况的见解 - 谢谢。

4 个答案:

答案 0 :(得分:11)

这是一个使用递归来解决问题的简单方法。它允许您通过传递“点”属性名称来遍历对象图。它适用于属性和字段。

static class PropertyInspector 
{
    public static object GetObjectProperty(object item,string property)
    {
        if (item == null)
            return null;

        int dotIdx = property.IndexOf('.');

        if (dotIdx > 0)
        {
            object obj = GetObjectProperty(item,property.Substring(0,dotIdx));

            return GetObjectProperty(obj,property.Substring(dotIdx+1));
        }

        PropertyInfo propInfo = null;
        Type objectType = item.GetType();

        while (propInfo == null && objectType != null)
        {
            propInfo = objectType.GetProperty(property, 
                      BindingFlags.Public 
                    | BindingFlags.Instance 
                    | BindingFlags.DeclaredOnly);

            objectType = objectType.BaseType;
        }

        if (propInfo != null)
            return propInfo.GetValue(item, null);

        FieldInfo fieldInfo = item.GetType().GetField(property, 
                      BindingFlags.Public | BindingFlags.Instance);

        if (fieldInfo != null)
            return fieldInfo.GetValue(item);

        return null;
    }
}

示例:

class Person
{
   public string Name { get; set; }
   public City City { get; set; }
}

class City
{
   public string Name { get; set; }
   public string ZipCode { get; set; }
}

Person person = GetPerson(id);

Console.WriteLine("Person name = {0}", 
      PropertyInspector.GetObjectProperty(person,"Name"));

Console.WriteLine("Person city = {0}",
      PropertyInspector.GetObjectProperty(person,"City.Name"));

答案 1 :(得分:3)

我猜你只需要将其分解为几个步骤,而不是试图在一个步骤中完成所有操作,例如:

// First get the customer group Property...
CustomerGroup customerGroup = getValue<Customer>(customer, "Group");
// Then get the name of the group...
if(customerGroup != null)
{
    string customerGroupName = getValue<CustomerGroup>(customerGroup, "name");
}

答案 2 :(得分:3)

在System.Web.UI命名空间中,有一种方法可以做到这一点:

DataBinder.Eval(source, expression);

答案 3 :(得分:0)

由于Group是客户的财产,它本身拥有财产名称,因此您也必须采用这种方式。 但是由于 '。'不能成为属性名称的一部分,您可以轻松使用String.Substring从字符串中删除第一个属性名称并递归调用您的方法。