C#反射属性顺序

时间:2013-02-06 16:47:11

标签: c# reflection

我正在使用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 |

有没有办法按顺序获取字段?

5 个答案:

答案 0 :(得分:16)

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

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

由于可以要求每个属性声明它的类型,您可以在开头创建一个查找,为层次结构中的每个类提供一个数字,从您开始的类型一直到object by遍历BaseType的{​​{1}}属性,并按每个属性的声明类型的查找值排序:

Type

答案 1 :(得分:2)

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

也就是说,我一直认为元素是按源文件中的声明顺序返回的。在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();

如果您不希望依赖库,则代码是开源的,因此您可以选择所需的位。遍历算法可以是seen here(第443行)。

答案 2 :(得分:1)

所有您需要做的就是声明类型并反转列表

 var publicProperties = typeof(T).GetProperties()
                .GroupBy(p => p.DeclaringType)
                .Reverse()
                .SelectMany(g => g)
                .ToArray();

答案 3 :(得分:0)

作为另一种分类方法:

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;
    });

答案 4 :(得分:-1)

您可以从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;
}