我正在使用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 |
有什么方法可以完全按照该顺序获取字段?
我正在使用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 |
有什么方法可以完全按照该顺序获取字段?
类型中的字段不是“有序的”。这些方法中项目的顺序是一个实现细节,强烈建议不要依赖它们。
您应该自己订购这些项目,并期望它们可以从任何位置开始,以确保您的程序是健壮的而不是脆弱的。
由于可以向每个属性询问声明它的类型,因此您可以在开始时创建一个查找,为层次结构中的每个类提供一个编号,从您开始的类型一直到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]);
}
反射子系统的文档说您不能依赖返回元素的顺序。
也就是说,根据我的经验,元素是按照源文件中的声明顺序返回的。在 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 行)。
您所要做的就是通过声明类型进行分组并反转列表
 var publicProperties = typeof(T).GetProperties()
                .GroupBy(p => p.DeclaringType)
                .Reverse()
                .SelectMany(g => g)
                .ToArray();
作为排序的替代方法:
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;
    });
您可以从 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;
}