首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >`Type.GetProperties`属性顺序

`Type.GetProperties`属性顺序
EN

Stack Overflow用户
提问于 2012-01-15 18:33:43
回答 5查看 12K关注 0票数 29

短版

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

详细版本

我实现了用于Type.GetProperties状态的MSDN文档:

GetProperties方法不按特定顺序返回属性,例如字母顺序或声明顺序。您的代码不能依赖于返回属性的顺序,因为顺序是不同的。

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

示例:

代码语言:javascript
复制
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);
    }
}

输出:

代码语言:javascript
复制
Simple Properties:
        FieldB
        FieldA
        FieldC

这种情况仅略有不同的一种情况是,当所涉类型的父类也具有属性时:

代码语言:javascript
复制
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);

    }
}

输出:

代码语言:javascript
复制
Parent Properties:
        ParentFieldB
        ParentFieldA
        ParentFieldC
Child Properties:
        ChildFieldB
        ChildFieldA
        ChildFieldC
        ParentFieldB
        ParentFieldA
        ParentFieldC

这意味着当发现属性时,GetProperties方法从下向上遍历继承链。这很好,可以按这样的方式处理。

问题:

  1. 是否有特定的情况下,所描述的行为会有所不同,我已经错过了?
  2. 如果不推荐取决于订单,那么推荐的方法是什么?

一个看似显而易见的解决方案是定义一个自定义属性,该属性指示属性应该显示的顺序(类似于DataMember属性上的DataMember属性)。类似于:

代码语言:javascript
复制
public class PropOrderAttribute : Attribute
{
    public int SeqNbr { get; set; }
}

然后实施如下:

代码语言:javascript
复制
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个属性,并且需要在前两个属性之间添加一个属性,则这将成为一个严重的维护问题。

更新

这里所示的例子只是为了说明而已。在我的特定场景中,我使用类定义消息格式,然后遍历类的属性并获取它们的属性,以查看消息中的特定字段应该如何删除。消息中字段的顺序是重要的,所以我类中属性的顺序需要是重要的。

它目前的工作方式只是迭代来自GetProperties的返回集合,但是由于文档声明不建议我了解为什么以及我还有什么其他选项?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-01-15 18:37:08

命令没有得到保证,无论发生什么..。时有发生。

明显的情况是,这种情况可能发生变化:

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

但更微妙的情况是:部分类。如果一个类被拆分为多个文件,则它们的使用顺序根本没有定义。请参阅跨部分类的“文本顺序”是否正式定义?

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

但想象一下

档案1

代码语言:javascript
复制
partial class Foo {
     public int A {get;set;}
}

档案2

代码语言:javascript
复制
partial class Foo {
    public int B {get;set:}
}

但是,在A和B之间没有正式的声明顺序,请参见链接的帖子,看看它是如何发生的。

重新编辑;最好的方法是分别指定封送处理信息;一种常见的方法是使用接受数字顺序的自定义属性,并使用该属性来修饰成员。然后,您可以根据这个数字订购。protobuf做了一些非常类似的事情,坦率地说,我建议在这里使用一个现有的序列化库:

代码语言:javascript
复制
[ProtoMember(n)]
public int Foo {get;set;}

其中"n“是整数。具体来说,在protobuf的情况下,也有一个API分别指定这些数字,当类型不在您的直接控制之下时,这个API非常有用。

票数 16
EN

Stack Overflow用户

发布于 2015-07-06 18:37:57

不管它的价值是什么,按MetadataToken分类似乎对我有用。

代码语言:javascript
复制
GetType().GetProperties().OrderBy(x => x.MetadataToken)

原始文章(链接断裂,此处列出原因):http://www.sebastienmahe.com/v3/seb.blog/2010/03/08/c-reflection-getproperties-kept-in-declaration-order/

票数 10
EN

Stack Overflow用户

发布于 2014-05-28 18:36:42

我使用自定义属性来自己添加必要的元数据(它与REST类似的服务一起使用并返回CRLF分隔的Key=Value对)。

首先,一个自定义属性:

代码语言:javascript
复制
class ParameterOrderAttribute : Attribute
{
    public int Order { get; private set; }
    public ParameterOrderAttribute(int order)
    {
        Order = order;
    }
}

然后,装饰你的课程:

代码语言:javascript
复制
class Response : Message
{
    [ParameterOrder(0)]
    public int Code { get; set; }
}

class RegionsResponse : Response 
{
    [ParameterOrder(1)]
    public string Regions { get; set; }
}

class HousesResponse : Response
{
    public string Houses { get; set; }
}

将PropertyInfo转换为可排序int的简便方法:

代码语言:javascript
复制
    private int PropertyOrder(PropertyInfo propInfo)
    {
        int output;
        var orderAttr = (ParameterOrderAttribute)propInfo.GetCustomAttributes(typeof(ParameterOrderAttribute), true).SingleOrDefault();
        output = orderAttr != null ? orderAttr.Order : Int32.MaxValue;
        return output;
    }

更好的是,写是作为一个扩展:

代码语言:javascript
复制
static class PropertyInfoExtensions
{
    private static int PropertyOrder(this PropertyInfo propInfo)
    {
        int output;
        var orderAttr = (ParameterOrderAttribute)propInfo.GetCustomAttributes(typeof(ParameterOrderAttribute), true).SingleOrDefault();
        output = orderAttr != null ? orderAttr.Order : Int32.MaxValue;
        return output;
    }
}

最后,您现在可以使用以下方法查询Type对象:

代码语言:javascript
复制
        var props = from p in type.GetProperties()
                    where p.CanWrite
                    orderby p.PropertyOrder() ascending
                    select p;
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8872254

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档