当前位置:  开发笔记 > 编程语言 > 正文

使用GetProperty获取子属性的最佳方法

如何解决《使用GetProperty获取子属性的最佳方法》经验,为你挑选了3个好方法。

你需要这样的东西:

PropertyInfo addressProperty = typeof(Customer).GetProperty("Address");
ProportyInfo zipCodeProperty = addressProperty.PropertyType.GetProperty("ZipCode");

object address = addressProperty.GetValue(customer, null);
object zipCode = zipCodeProperty.GetValue(address, null);

基本上,如果你想要一个字符串"Address.ZipCode"并向下导航,你需要将其拆分为"." 然后在每一步调用适当类型的GetProperty以获取属性本身,然后使用PropertyInfo.GetValue获取链中的下一个值.像这样的东西:

public static object FollowPropertyPath(object value, string path)
{
    Type currentType = value.GetType();

    foreach (string propertyName in path.Split('.'))
    {
        PropertyInfo property = currentType.GetProperty(propertyName);
        value = property.GetValue(value, null);
        currentType = property.PropertyType;
    }
    return value;
}

像这样称呼它:

object zipCode = FollowPropertyPath(customer, "Address.ZipCode");

请注意,这适用于属性的编译时类型.如果您希望它处理执行时间类型(例如,如果customer.Address没有ZipCode属性,但是Address确实返回的实际类型)则更property.PropertyType改为property.GetType().

另请注意,这没有任何错误处理等:)



1> Jon Skeet..:

你需要这样的东西:

PropertyInfo addressProperty = typeof(Customer).GetProperty("Address");
ProportyInfo zipCodeProperty = addressProperty.PropertyType.GetProperty("ZipCode");

object address = addressProperty.GetValue(customer, null);
object zipCode = zipCodeProperty.GetValue(address, null);

基本上,如果你想要一个字符串"Address.ZipCode"并向下导航,你需要将其拆分为"." 然后在每一步调用适当类型的GetProperty以获取属性本身,然后使用PropertyInfo.GetValue获取链中的下一个值.像这样的东西:

public static object FollowPropertyPath(object value, string path)
{
    Type currentType = value.GetType();

    foreach (string propertyName in path.Split('.'))
    {
        PropertyInfo property = currentType.GetProperty(propertyName);
        value = property.GetValue(value, null);
        currentType = property.PropertyType;
    }
    return value;
}

像这样称呼它:

object zipCode = FollowPropertyPath(customer, "Address.ZipCode");

请注意,这适用于属性的编译时类型.如果您希望它处理执行时间类型(例如,如果customer.Address没有ZipCode属性,但是Address确实返回的实际类型)则更property.PropertyType改为property.GetType().

另请注意,这没有任何错误处理等:)



2> Mike Fuchs..:

Jon Skeet的答案很好,我不得不扩展他的方法,以便考虑属性路径中的派生实例:

public static class ReflectorUtil
{
    public static object FollowPropertyPath(object value, string path)
    {
        if (value == null) throw new ArgumentNullException("value");
        if (path == null) throw new ArgumentNullException("path");

        Type currentType = value.GetType();

        object obj = value;
        foreach (string propertyName in path.Split('.'))
        {
            if (currentType != null)
            {
                PropertyInfo property = null;
                int brackStart = propertyName.IndexOf("[");
                int brackEnd = propertyName.IndexOf("]");

                property = currentType.GetProperty(brackStart > 0 ? propertyName.Substring(0, brackStart) : propertyName);
                obj = property.GetValue(obj, null);

                if (brackStart > 0)
                {
                    string index = propertyName.Substring(brackStart + 1, brackEnd - brackStart - 1);
                    foreach (Type iType in obj.GetType().GetInterfaces())
                    {
                        if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
                        {
                            obj = typeof(ReflectorUtil).GetMethod("GetDictionaryElement")
                                                 .MakeGenericMethod(iType.GetGenericArguments())
                                                 .Invoke(null, new object[] { obj, index });
                            break;
                        }
                        if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(IList<>))
                        {
                            obj = typeof(ReflectorUtil).GetMethod("GetListElement")
                                                 .MakeGenericMethod(iType.GetGenericArguments())
                                                 .Invoke(null, new object[] { obj, index });
                            break;
                        }
                    }
                }

                currentType = obj != null ? obj.GetType() : null; //property.PropertyType;
            }
            else return null;
        }
        return obj;
    }

    public static TValue GetDictionaryElement(IDictionary dict, object index)
    {
        TKey key = (TKey)Convert.ChangeType(index, typeof(TKey), null);
        return dict[key];
    }

    public static T GetListElement(IList list, object index)
    {
        return list[Convert.ToInt32(index)];
    }

}

使用property.PropertyType将获得在obj类上定义的属性类型,而使用obj.GetType()将获得属性实例的实际类型.

编辑:@Oliver - 你是绝对正确的,谢谢你的注意.我调整了方法以允许通用列表和词典.虽然我不喜欢解析部分,但我在这个线程中使用了Marc Gravell的聪明主意来获取索引器属性的值.



3> Marc Gravell..:

现有答案很好; 只是另一种观点:在许多场景中,最好使用System.ComponentModel而不是直接反射,因为这允许运行时属性场景 - 即DataTable的DataView如何将列作为属性公开.

性能方面 - 默认情况下这大致相同,但是如果您正在做很多这样的事情(例如,批量数据导入/导出),那么使用这种方法实际上可以获得显着的性能提升,这得益于HyperDescriptor.

要使用System.ComponentModel,代码类似,但略有不同:

static void Main()
{
    object obj = new Customer { Address = new Address { ZipCode = "abcdef" } };

    object address = GetValue(obj, "Address");
    object zip = GetValue(address, "ZipCode");

    Console.WriteLine(zip);
}
static object GetValue(object component, string propertyName)
{
    return TypeDescriptor.GetProperties(component)[propertyName].GetValue(component);
}

然后,这将为您提供相同的处理,就像您使用数据绑定绑定到"Address.ZipCode"(对列表等一些细节进行掩饰).

(请注意,如果您知道这是预期的类型,您可以将zip转换为字符串等)

要从深层路径获取值(包括处理数据绑定使用的相同列表),您可以使用以下内容:

static object ResolveValue(object component, string path) {
    foreach(string segment in path.Split('.')) {
        if (component == null) return null;
        if(component is IListSource) {
            component = ((IListSource)component).GetList();
        }
        if (component is IList) {
            component = ((IList)component)[0];
        }
        component = GetValue(component, segment);
    }
    return component;
}

列表内容粗略地反映了常规数据绑定的行为(尽管它省略了一些事情,如绑定上下文,货币管理器等)

推荐阅读
罗文彬2502852027
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有