Краткая версия
В документации MSDN для Type.GetProperties
указано, что возвращаемая коллекция не гарантируется в алфавитном порядке или порядке декларации, хотя выполняется простая тест показывает, что в целом он возвращается в порядке объявления. Существуют ли конкретные сценарии, которые вы знаете о том, где это не так? Помимо этого, какова предлагаемая альтернатива?
Подробная версия
Я понимаю документацию MSDN для Type.GetProperties
:
Метод GetProperties не возвращает свойства в определенном порядок, например, алфавитный или порядок объявления. Ваш код не должен зависят от порядка возврата свойств, поскольку это порядок меняется.
поэтому нет никакой гарантии, что коллекция, возвращаемая методом, будет упорядочена любым конкретным способом. На основании некоторых тестов я обнаружил, что возвращаемые свойства отображаются в том порядке, в котором они определены в типе.
Пример:
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
поднимает цепочку наследования снизу вверх при обнаружении свойств. Это прекрасно и может быть обработано как таковое.
Вопросы:
- Существуют ли конкретные ситуации, когда описанное поведение будет отличаться от того, что я пропустил?
- Если в зависимости от заказа не рекомендуется, то какой рекомендуемый подход?
Одним из кажущихся очевидным решений было бы определить пользовательский атрибут, который указывает порядок, в котором должны появляться свойства (аналогично свойству Order
в атрибуте DataMember
). Что-то вроде:
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 свойств, и вам нужно добавить один из двух первых.
UPDATE
Примеры, показанные здесь, просто для демонстрационных целей. В моем конкретном сценарии я определяю формат сообщения с помощью класса, затем перебираю свойства класса и захватываю его атрибуты, чтобы увидеть, как конкретное поле в сообщении должно быть демаршалировано. Порядок полей в сообщении значителен, поэтому порядок свойств в моем классе должен быть значительным.
В настоящее время он работает, просто перебирая возвращаемую коллекцию из GetProperties
, но поскольку в документации указано, что это не рекомендуется, я хотел понять, почему и какой другой вариант у меня есть?