Как я могу отсортировать поля, возвращаемые Type.GetFields () по порядку их объявления? - PullRequest
3 голосов
/ 02 апреля 2012

Type.GetFields () не возвращает поля в определенном порядке, но я хочу отсортировать их по порядку объявления. Как я могу это сделать? Я не видел свойства index в FieldInfo или чего-либо подобного.

Мотивация: Я хочу реализовать решение для битовых полей, подобное тому, которое есть в в этом ответе , но, как уже упоминалось во втором комментарии, порядок не гарантируется.

РЕДАКТИРОВАТЬ: уточнение - я не хочу создавать этот код, чтобы полагаться на этот порядок. Я хочу создать этот код для анализа существующих двоичных данных, которые уже имеют определенный порядок.


РЕДАКТИРОВАТЬ 2 (пост-ответ): Я выбрал ответ, который полностью отвечает на вопрос и который работал должным образом в моих тестах, но, как примечание, решение с битовыми полями проблематично:

При чтении значения из битового поля вы получаете целое число без знака (некоторого размера), но затем вы не можете привести его должным образом в соответствии с фактическим типом поля (byte, bool, int), который вы получаете во время выполнения из FieldInfo. Вы можете сделать это с явными условными выражениями во время выполнения (if type.Equals(typeof(bool)) и т. Д.), Но это немного уродливо.

В итоге я использовал C ++ / CLI, что значительно упростило эту задачу.

Ответы [ 5 ]

5 голосов
/ 02 апреля 2012

Вы можете написать собственный атрибут, который объявляет порядок. Затем для каждого поля найдите этот атрибут. Используйте значения для сортировки.

Это не было бы автоматически, но это было бы очень детерминистическим способом.

Пример использования:

[Index(0)]
private int myField;

[Index(1)]
private int myOtherField;
2 голосов
/ 02 апреля 2012

Вы можете добавить информацию о местоположении к атрибуту

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

Преимущество по алфавиту в том, что вы можете контролировать положение новых полей, которые вы добавляете позже, и, таким образом, избегать изменения положения существующих полей.

1 голос
/ 02 апреля 2012

Вы можете расширить атрибут 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; } }
}

Затем вручную добавить индекс во все поля, получить типы в списке и отсортировать список по индексу атрибута.

0 голосов
/ 01 октября 2014

по этой ссылке говорит, что нужно сортировать по MetadataToken, чтобы получить порядок замедления.что означает что-то вроде:

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

Я не очень понимаю, как это работает, но сейчас он работал нормально для меня.

0 голосов
/ 02 апреля 2012

Вы можете использовать Linq to Object и написать код, подобный этому:

var fields = type.GetFields().OrderBy(f => f.Name).ToArray();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...