Get properties in order of declaration using reflection
On .net 4.5 (and even .net 4.0 in vs2012) you can do much better with reflection using clever trick with [CallerLineNumber]
attribute, letting compiler insert order into your properties for you:
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class OrderAttribute : Attribute
{
private readonly int order_;
public OrderAttribute([CallerLineNumber]int order = 0)
{
order_ = order;
}
public int Order { get { return order_; } }
}
public class Test
{
//This sets order_ field to current line number
[Order]
public int Property2 { get; set; }
//This sets order_ field to current line number
[Order]
public int Property1 { get; set; }
}
And then use reflection:
var properties = from property in typeof(Test).GetProperties()
where Attribute.IsDefined(property, typeof(OrderAttribute))
orderby ((OrderAttribute)property
.GetCustomAttributes(typeof(OrderAttribute), false)
.Single()).Order
select property;
foreach (var property in properties)
{
//
}
If you have to deal with partial classes, you can additionaly sort the properties using [CallerFilePath]
.
If you're going the attribute route, here's a method I've used in the past;
public static IOrderedEnumerable<PropertyInfo> GetSortedProperties<T>()
{
return typeof(T)
.GetProperties()
.OrderBy(p => ((Order)p.GetCustomAttributes(typeof(Order), false)[0]).Order);
}
Then use it like this;
var test = new TestRecord { A = 1, B = 2, C = 3 };
foreach (var prop in GetSortedProperties<TestRecord>())
{
Console.WriteLine(prop.GetValue(test, null));
}
Where;
class TestRecord
{
[Order(1)]
public int A { get; set; }
[Order(2)]
public int B { get; set; }
[Order(3)]
public int C { get; set; }
}
The method will barf if you run it on a type without comparable attributes on all of your properties obviously, so be careful how it's used and it should be sufficient for requirement.
I've left out the definition of Order : Attribute as there's a good sample in Yahia's link to Marc Gravell's post.
According to MSDN MetadataToken
is unique inside one Module - there is nothing saying that it guarantees any order at all.
EVEN if it did behave the way you want it to that would be implementation-specific and could change anytime without notice.
See this old MSDN blog entry.
I would strongly recommend to stay away from any dependency on such implementation details - see this answer from Marc Gravell.
IF you need something at compile time you could take a look at Roslyn (although it is in a very early stage).