【问题标题】:C# - How can I sort the fields returned by Type.GetFields() by their declaration order?C# - 如何按声明顺序对 Type.GetFields() 返回的字段进行排序?
【发布时间】:2012-04-02 13:22:43
【问题描述】:

Type.GetFields() 不按特定顺序返回字段,但我想按声明顺序对它们进行排序。我怎样才能做到这一点?我没有在 FieldInfo 或任何具有类似功能的东西中看到“索引”属性。

动机:我想实现一个类似于this answer 的位域解决方案,但正如第二条评论中提到的那样,不能保证顺序。

编辑: 澄清 - 我不想创建此代码来依赖此排序。我想创建此代码来解析已经具有一定顺序的现有二进制数据。


EDIT 2(post answer):我选择了一个完全回答问题的答案,并且在我的测试中工作正常,但作为旁注,位域解决方案是有问题的:

从位字段读取值时,您会得到一个无符号整数(一定大小),但是您无法根据您在运行时获得的实际字段类型(字节、布尔值、整数)正确转换它字段信息。您可以使用运行时显式条件(if type.Equals(typeof(bool)) 等)来做到这一点,但这有点难看。

我最终使用了 C++/CLI,这让这变得非常简单。

【问题讨论】:

  • 什么是“声明顺序”,面对部分类这样的特性?如果您想要一个明确的、明确的、按字母顺序排列的,那么目标似乎更简单。
  • @Damien_The_Unbeliever - 请参阅上面的说明。
  • @Asaf - 查看二进制文件是一种危险的方式,因为编译器可能会以不同方式优化事物。
  • @DanielA.White - 不是“可执行二进制文件”,而是由外部工具保存的特定格式的二进制数据。

标签: c# reflection


【解决方案1】:

您可以编写一个自定义属性来声明订单。然后对于每个字段,查找该属性。使用值进行排序。

这不会是自动的,但会是一种非常确定的方式。

使用示例:

[Index(0)]
private int myField;

[Index(1)]
private int myOtherField;

【讨论】:

  • 有可能,但很麻烦。每个字段还需要 bitfield 属性,我可以只命名字段,这样我就可以按名称对其进行排序,而无需编写额外的类。
  • @Asaf:这迫使你使用可能不理想的名称,并且意味着稍后重构的人可能会在没有意识到的情况下搞砸事情。我强烈建议您使用这个解决方案 - 让每条信息都意味着一件事
  • @Asaf - 您可以随时将位域属性与此结合使用。
【解决方案2】:

您可以在属性中添加位置信息

[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class BitfieldAttribute : Attribute 
{ 
    public BitfieldAttribute(int position, int length) 
    { 
        this.Position = position; 
        this.Length = length; 
    } 

    public int Position { get; private set; }

    public int Length { get; private set; }
}

然后你可以像这样遍历字段

foreach (FieldInfo fld in type.GetFields().OrderBy(f => f.Position)) {
    ...
}

这个属性会这样使用

struct PESHeader 
{ 
    [Bitfield(0, 2)] 
    public uint reserved; 

    [Bitfield(1, 2)] 
    public uint scrambling_control; 

    [Bitfield(2, 1)] 
    public uint priority; 

    [Bitfield(3, 1)] 
    public uint data_alignment_indicator; 

    [Bitfield(4, 1)] 
    public uint copyright; 

    [Bitfield(5, 1)] 
    public uint original_or_copy; 
}

相对于字母顺序的优点是您可以控制以后添加的新字段的位置,从而避免现有字段的位置发生变化。

【讨论】:

    【解决方案3】:

    您可以像这样扩展 BitFieldLength 属性:

    sealed class BitfieldLengthAttribute : Attribute
    {
        uint index;
        uint length;
    
        public BitfieldLengthAttribute(uint index, uint length)
        {
            this.index = index;
            this.length = length;
        }
    
        public uint Index { get { return index; } }
        public uint Length { get { return length; } }
    }
    

    然后手动为所有字段添加索引,检索列表中的类型并根据属性索引对列表进行排序。

    【讨论】:

      【解决方案4】:

      您可以使用 Linq to Object 并编写如下代码:

      var fields = type.GetFields().OrderBy(f => f.Name).ToArray();
      

      【讨论】:

        【解决方案5】:

        在这个link 它说按 MetadataToken 排序以获得减速顺序。 这意味着类似:

                    IEnumerable<FieldInfo> fields = t.GetFields().OrderBy(f=>f.MetadataToken);
        

        我不太了解它的工作原理,但现在它对我来说很好。

        【讨论】:

        • 欢迎来到 Stack Overflow。链接可能会中断,因此不鼓励仅链接的答案。强烈建议包含链接中的关键部分。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-02
        相关资源
        最近更新 更多