Get properties in declaration order 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, when using GetProperties()

order cannot be guaranteed

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

But I read that there is a workaround by ordering properties using a MetadataToken . So my question is, is it safe? I can not find information about MSDN. Or is there any other way to solve this problem?

My current implementation is as follows:

 var props = typeof(T) .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .OrderBy(x => x.MetadataToken); 
+49
reflection c # properties
Jan 30 '12 at 10:09
source share
6 answers

According to MSDN, the MetadataToken is unique within one module - there is nothing to say that it guarantees any order at all.

EVEN if it behaves the way you want it to be related to the implementation and could change at any time without notice.

Check out this old one .

I would strongly recommend avoiding any dependencies on such implementation details - see this answer from Mark Gravel .

If you need something at compile time, you can take a look at Roslyn (although it is at a very early stage).

+12
Jan 30 '12 at 11:03
source share

In .net 4.5 (and even .net 4.0 in vs2012) you can do much better with reflection using a smart trick with the [CallerLineNumber] attribute, allowing you to arrange the compiler order in its 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 further sort the properties using [CallerFilePath] .

+94
Aug 01 '13 at 15:30
source share

If you intend to use the attribute route, the method that I used in the past is used here;

 public static IOrderedEnumerable<PropertyInfo> GetSortedProperties<T>() { return typeof(T) .GetProperties() .OrderBy(p => ((Order)p.GetCustomAttributes(typeof(Order), false)[0]).Order); } 

Then use it as follows:

 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 be barf if you run it by type without comparable attributes across all your properties, so be careful how it is used, and this should be enough for the requirement.

I declined the definition of Order: Attribute, since Yahia has a good sample link to Mark Gravell’s post.

+9
Jan 30 2018-12-01T00:
source share

I tested sorting by MetadataToken.

Some users claim that this is somehow a bad / unreliable approach, but I have not seen any evidence for this yet - maybe you can post some snipet code here when this approach does not work?

About backward compatibility - while you are currently working on your .net 4 / .net 4.5 - Microsoft does .net 5 or higher, so you can pretty much assume that this sorting method will not be broken in the future.

Of course, by 2017, when you will be upgrading to .net9, you will encounter a break in compatibility, but by this time the guys from Microsoft will probably figure out the "official sorting mechanism." It makes no sense to go back or break things.

Playing with additional attributes to arrange properties also takes time and implementation - why bother if MetadataToken sorting works?

+3
Mar 09 '15 at 20:18
source share

You can use DisplayAttribute in System.Component.DataAnnotations instead of a custom attribute. In any case, your requirement must do something with the display.

+1
Oct 05 '16 at 16:14
source share

If you are happy with the addiction, Marc Gravell Protobuf-Net can be used for this without worrying about the best way to implement reflection and caching, etc. Just decorate your fields using [ProtoMember] and then access the fields in numerical order using:

 MetaType metaData = ProtoBuf.Meta.RuntimeTypeModel.Default[typeof(YourTypeName)]; metaData.GetFields(); 
0
Dec 14
source share



All Articles