3

我正在使用https://stackoverflow.com/a/531388/528131中的代码从基础成功检索对象实例的所有属性,问题是派生类型的属性首先被迭代。由于协议的性质,我首先需要基本属性。

x |
y | B
z |
w | A

B 和 A 是类,B 派生自 A。x、y、z 是 B 的属性,w 是 A 的属性

这是 A.GetProperties(); 的方案。正在返回。我需要这个:

w | A
x |
y | B
z |

有什么方法可以完全按照该顺序获取字段?

4

5 回答 5

17

类型中的字段不是“有序的”。这些方法中项目的顺序是一个实现细节,强烈建议不要依赖它们。

您应该自己订购这些项目,并期望它们可以从任何位置开始,以确保您的程序是健壮的而不是脆弱的。

由于可以向每个属性询问声明它的类型,因此您可以在开始时创建一个查找,为层次结构中的每个类提供一个编号,从您开始的类型一直到object通过遍历BaseType属性Type并按顺序排列每个属性的声明类型的查找值:

public static IEnumerable<PropertyInfo> GetOrderedProperties(Type type)
{
    Dictionary<Type, int> lookup = new Dictionary<Type, int>();

    int count = 0;
    lookup[type] = count++;
    Type parent = type.BaseType;
    while (parent != null)
    {
        lookup[parent] = count;
        count++;
        parent = parent.BaseType;
    }

    return type.GetProperties()
        .OrderByDescending(prop => lookup[prop.DeclaringType]);
}
于 2013-02-06T16:49:59.747 回答
3

反射子系统的文档说您不能依赖返回元素的顺序。

也就是说,根据我的经验,元素是按照源文件中的声明顺序返回的。在 Mono 或 .NET 的未来版本中,这可能是真的,也可能不是。

尽管有上述情况,如果您希望继续,您最好的选择是使用该BindingFlags.DeclaredOnly选项并手动遍历继承层次结构(在子类型之前扫描基本类型以使它们以正确的顺序排列)。您应该以这样一种方式编写代码,即单个声明类型的属性排序无关紧要(例如,按名称排序);如果 .NET 框架的行为发生变化,这将使您的代码更加健壮。

Fasterflect这样做(主要是为了能够过滤掉已被覆盖的虚拟属性)。它还具有帮助器来获取属性,无论是否过滤,使用它自己的和更强大的Flags选择器参数。

如果单个类型中元素的顺序不重要,您可以像这样获得列表(使用 Fasterflect):

var properties = type.Properties().Reverse().ToList();

您应该知道,当以这种方式反映时(通过遍历并仅获取声明的属性),将包含多次覆盖的属性。Fasterflect 提供了从结果中过滤这些的选项:

var properties = type.Properties( Flags.InstancePublic | Flags.ExcludeBackingMembers ).Reverse().ToList();

如果您不想依赖该库,代码是开源的,因此您可以选择您需要的部分。可以在这里看到遍历算法(第 443 行)。

于 2013-02-06T16:54:25.700 回答
3

您所要做的就是通过声明类型进行分组并反转列表

 var publicProperties = typeof(T).GetProperties()
                .GroupBy(p => p.DeclaringType)
                .Reverse()
                .SelectMany(g => g)
                .ToArray();
于 2019-01-08T14:18:49.730 回答
1

作为排序的替代方法:

PropertyInfo[] properties = type.GetProperties(...);
Array.Sort(properties, (pi1, pi2) =>
    {
        if (pi1.DeclaringType.IsSubclassOf(pi2.DeclaringType))
           return 1;
        else if  (pi2.DeclaringType.IsSubclassOf(pi1.DeclaringType))
            return -1;
        else
            return 0;
    });
于 2013-02-06T17:07:49.093 回答
-1

您可以从 of 的实例中获取声明类型,PropertyInfo并按其与 的距离排序Object

我会这样做:

void Main()
{
    typeof(B).GetProperties()
    .Select((x,i) => new {
        Prop = x,
        DeclareOrder = i,
        InheritanceOrder = GetDepth(x.DeclaringType),
    })
    .OrderByDescending(x => x.InheritanceOrder)
    .ThenBy(x => x.DeclareOrder)
    .Dump();
}

public class A
{
    public string W {get; set;}
}

public class B : A
{
    public string X {get; set;}
    public string Y {get; set;}
    public string Z {get; set;}
}

static int GetDepth(Type t)
{
    int depth = 0;
    while (t != null)
    {
        depth++;
        t = t.BaseType;
    }
    return depth;
}
于 2013-02-06T16:59:19.433 回答