c# - `Type.GetProperties` 属性顺序

标签 c# reflection

精简版

Type.GetProperties 的 MSDN 文档指出它返回的集合不保证按字母顺序或声明顺序排列,尽管运行一个简单的测试表明它通常按声明顺序返回。您是否知道在某些特定情况下情况并非如此?除此之外,建议的替代方案是什么?

详细版

我了解 Type.GetProperties 的 MSDN 文档状态:

The GetProperties method does not return properties in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which properties are returned, because that order varies.

因此无法保证该方法返回的集合将以任何特定方式排序。根据一些测试,我发现相反的是,返回的属性按照它们在类型中定义的顺序出现。

示例:

class Simple
{
    public int FieldB { get; set; }
    public string FieldA { get; set; }
    public byte FieldC { get; set; }
}
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Simple Properties:");
        foreach (var propInfo in typeof(Simple).GetProperties())
            Console.WriteLine("\t{0}", propInfo.Name);
    }
}

输出:

Simple Properties:
        FieldB
        FieldA
        FieldC

其中一种情况只是略有不同,即所讨论的类型的父级也具有属性:

class Parent
{
    public int ParentFieldB { get; set; }
    public string ParentFieldA { get; set; }
    public byte ParentFieldC { get; set; }
}

class Child : Parent
{
    public int ChildFieldB { get; set; }
    public string ChildFieldA { get; set; }
    public byte ChildFieldC { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Parent Properties:");
        foreach (var propInfo in typeof(Parent).GetProperties())
            Console.WriteLine("\t{0}", propInfo.Name);

        Console.WriteLine("Child Properties:");
        foreach (var propInfo in typeof(Child).GetProperties())
            Console.WriteLine("\t{0}", propInfo.Name);

    }
}

输出:

Parent Properties:
        ParentFieldB
        ParentFieldA
        ParentFieldC
Child Properties:
        ChildFieldB
        ChildFieldA
        ChildFieldC
        ParentFieldB
        ParentFieldA
        ParentFieldC

这意味着 GetProperties 方法在发现属性时从下往上沿着继承链向上走。没关系,可以这样处理。

问题:

  1. 是否存在我错过的所描述行为会有所不同的特定情况?
  2. 如果不推荐根据顺序,那么推荐的方法是什么?

一个看似明显的解决方案是定义一个自定义属性,该属性指示属性应该出现的顺序(类似于 DataMember 上的 Order 属性 属性)。像这样的东西:

public class PropOrderAttribute : Attribute
{
    public int SeqNbr { get; set; }
}

然后实现如:

class Simple
{
    [PropOrder(SeqNbr = 0)]
    public int FieldB { get; set; }
    [PropOrder(SeqNbr = 1)]
    public string FieldA { get; set; }
    [PropOrder(SeqNbr = 2)]
    public byte FieldC { get; set; }
}

但正如许多人发现的那样,如果您的类型有 100 个属性并且您需要在前 2 个之间添加一个,这将成为一个严重的维护问题。

更新

此处显示的示例仅用于演示目的。在我的具体场景中,我使用类定义消息格式,然后遍历类的属性并获取它们的属性以查看消息中的特定字段应该如何解码。消息中字段的顺序很重要,因此我的类中的属性顺序需要很重要。

目前它仅通过迭代 GetProperties 的返回集合来工作,但由于文档指出不推荐这样做,我想了解原因以及我还有什么其他选择?

最佳答案

订单根本无法保证;无论发生什么……都会发生。

它可能会改变的明显情况:

  • 任何实现 ICustomTypeDescriptor 的东西
  • 任何带有 TypeDescriptionProvider 的东西

但更微妙的情况是:分部类。如果一个类被拆分成多个文件,那么它们的使用顺序根本就没有定义。参见 Is the "textual order" across partial classes formally defined?

当然,即使是单个(非部分)定义也没有定义;p

但想象一下

文件 1

partial class Foo {
     public int A {get;set;}
}

文件 2

partial class Foo {
    public int B {get;set:}
}

A 和 B 之间没有正式的声明顺序。不过,请参阅链接帖子以了解它倾向于如何发生。


重新编辑;最好的方法是单独指定编码(marshal)信息;一种常见的方法是使用采用数字顺序的自定义属性,并用它来装饰成员。然后,您可以根据此编号进行订购。 protobuf-net 做的事情非常相似,坦率地说,我建议在这里使用现有的序列化库:

[ProtoMember(n)]
public int Foo {get;set;}

其中“n”是一个整数。特别是在 protobuf-net 的情况下,还有一个 API 来单独指定这些数字,当类型不受您的直接控制时,这很有用。

关于c# - `Type.GetProperties` 属性顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8872254/

相关文章:

c# - 如何在 bin/Release 中为 Visual Studio 项目创建文件夹?

c# - 将 ddMMyyyy 格式的字符串转换为 DateTime

c# - 如何获得实例化泛型的参数类型?

sql - 在MonetDB中,我可以通过SQL命令获取数据库名称吗?

c# - 如何在使用 NLua 运行的脚本中对 .NET 枚举执行按位或运算?

java - 如何修剪通过使用 Java 反射获得的同一方法的变体?

c# - 是否可以用 C# 更改 CSS?

c# - 将具有对象列表的 json 绑定(bind)到模型

c# - Visual Studio 银光

c# - 获取数组长度