Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get properties in order of declaration using reflection

I need to get all the properties using reflection in the order in which they are declared in the class. According to MSDN the order can not be guaranteed when using GetProperties()

The GetProperties method does not return properties in a particular order, such as alphabetical or declaration order.

But I've read that there is a workaround by ordering the properties by the MetadataToken. So my question is, is that safe? I cant seem find any information on MSDN about it. Or is there any other way of solving this problem?

My current implementation looks as follows:

var props = typeof(T)    .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)    .OrderBy(x => x.MetadataToken); 
like image 302
Magnus Avatar asked Jan 30 '12 10:01

Magnus


2 Answers

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].

like image 192
ghord Avatar answered Sep 20 '22 08:09

ghord


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.

like image 33
Chris McAtackney Avatar answered Sep 22 '22 08:09

Chris McAtackney