`Type.GetProperties` property order
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.
I use custom attributes to add the necessary metadata myself (it's used with a REST like service which consumes and returns CRLF delimited Key=Value pairs.
First, a custom attribute:
class ParameterOrderAttribute : Attribute
{
public int Order { get; private set; }
public ParameterOrderAttribute(int order)
{
Order = order;
}
}
Then, decorate your classes:
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; }
}
A handy method for converting a PropertyInfo into a sortable int:
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;
}
Even better, write is as an extension:
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;
}
}
Finally you can now query your Type object with:
var props = from p in type.GetProperties()
where p.CanWrite
orderby p.PropertyOrder() ascending
select p;
For what it's worth, sorting by MetadataToken seemed to work for me.
GetType().GetProperties().OrderBy(x => x.MetadataToken)
Original Article (broken link, just listed here for attribution): http://www.sebastienmahe.com/v3/seb.blog/2010/03/08/c-reflection-getproperties-kept-in-declaration-order/