Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`Type.GetProperties` property order

Tags:

c#

reflection

Short Version

The MSDN documentation for Type.GetProperties states that the collection it returns is not guaranteed to be in alphabetical or declaration order, though running a simple test shows that in general it is returned in declaration order. Are there specific scenarios that you know of where this is not the case? Beyond that, what is the suggested alternative?

Detailed Version

I realize the MSDN documentation for Type.GetProperties states:

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.

so there is no guarantee that the collection returned by the method will be ordered any specific way. Based on some tests, I've found to the contrary that the properties returned appear in the order they're defined in the type.

Example:

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

Output:

Simple Properties:         FieldB         FieldA         FieldC 

One such case that this differs only slightly is when the type in question has a parent who also has properties:

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

Output:

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

Which means the GetProperties method walks up the inheritance chain from bottom up when discovering the properties. That's fine and can be handled as such.

Questions:

  1. Are there specific situations where the described behavior would differ that I've missed?
  2. If depending on the order is not recommended then what is the recommended approach?

One seemingly obvious solution would be to define a custom attribute which indicates the order in which the properties should appear (Similar to the Order property on the DataMember attribute). Something like:

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

And then implement such as:

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

But as many have found, this becomes a serious maintenance problem if your type has 100 properties and you need to add one between the first 2.

UPDATE

The examples shown here are simply for demonstrative purposes. In my specific scenario, I define a message format using a class, then iterate through the properties of the class and grab their attributes to see how a specific field in the message should be demarshaled. The order of the fields in the message is significant so the order of the properties in my class needs to be significant.

It works currently by just iterating over the return collection from GetProperties, but since the documentation states it is not recommended I was looking to understand why and what other option do I have?

like image 391
M.Babcock Avatar asked Jan 15 '12 18:01

M.Babcock


People also ask

What is GetProperties C#?

GetProperties() Returns all the public properties of the current Type.

What is C# reflection?

Reflection provides objects (of type Type) that describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties.


1 Answers

The order simply isn't guaranteed; whatever happens.... Happens.

Obvious cases where it could change:

  • anything that implements ICustomTypeDescriptor
  • anything with a TypeDescriptionProvider

But a more subtle case: partial classes. If a class is split over multiple files, the order of their usage is not defined at all. See Is the "textual order" across partial classes formally defined?

Of course, it isn't defined even for a single (non-partial) definition ;p

But imagine

File 1

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

File 2

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

There is no formal declaration order here between A and B. See the linked post to see how it tends to happen, though.


Re your edit; the best approach there is to specify the marshal info separately; a common approach would be to use a custom attribute that takes a numeric order, and decorate the members with that. You can then order based on this number. protobuf-net does something very similar, and frankly I'd suggest using an existing serialization library here:

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

Where "n" is an integer. In the case of protobuf-net specifically, there is also an API to specify these numbers separately, which is useful when the type is not under your direct control.

like image 181
Marc Gravell Avatar answered Sep 25 '22 00:09

Marc Gravell