Grant H.
Grant H.

Reputation: 3717

How to add an attribute to a property and use it to order the members

How can I mark properties with an order attribute of some kind to help me iterate through them in order, to read a delimited file.

The classes were created with a property for each column, and I'd like to write a routine to handle it instead of doing it by hand.

Something like:

[Order(1)]
public string Field1 { get; set; }

[Order(2)]
public string Field2 { get; set; }

Then something like:

MemberInfo[] myMembers = myType.GetMembers()
    .OrderBy(something here or in a loop);

Any thoughts?

Upvotes: 2

Views: 465

Answers (4)

Martin Booth
Martin Booth

Reputation: 8595

You need an OrderAttribute class:

public class OrderAttribute : Attribute
{
    public OrderAttribute(int value)
    {
        this.Value = value;
    }

    public int Value { get; private set; }
}

Then, you can order by the property as follows:

MemberInfo[] myMembers = typeof(object).GetMembers()
    .OrderBy(m => m.GetCustomAttribute<OrderAttribute>().Value);

This is just a basic example of how to do this, I would recommend checking that your member actually has this attribute, and throwing either an appropriate error if it doesn't, or assuming a default value

Upvotes: 3

RlyDontKnow
RlyDontKnow

Reputation: 129

I would do that like that:

var members = myType.GetMembers()
                .Where(m => Attribute.IsDefined(m, typeof(OrderAttribute)))
                .OrderBy(m => m.GetCustomAttribute<OrderAttribute>().Order);

I check if OrderAttribute is defined so it wont throw null reference exception.

OrderAttribute.cs

public class OrderAttribute : Attribute
{
    public OrderAttribute(int order)
    {
        Order = order;
    }

    public int Order { get; private set; }
}

Upvotes: 0

Daniel Kereama
Daniel Kereama

Reputation: 951

What you are proposing is doable.

Create an attribute:

public class OrderAttribute : Attribute
{
    public int Order { get; private set; }
    public OrderAttribute(int order)
    {
        Order = order;
    }
}

Then in your OrderBy call get the OrderAttribute.Order field via reflection also. It would probably be better to put that logic in its own method or create an extension method on PropertyInfo.

SO it would look like this:

MemberInfo[] myMembers = myType.GetMembers()
.OrderBy(m => m.GetAttribute<OrderAttribute>().Order);

I created a generic extension method to handle attribute retrieval.

    public static TAttribute GetAttribute<TAttribute>(this object obj) 
        where TAttribute : Attribute
    {
        return obj.GetType().GetAttribute<TAttribute>();
    }


    public static TAttribute GetAttribute<TAttribute>(this ICustomAttributeProvider propInfo, bool inherit = true) 
        where TAttribute : Attribute
    {
        return (TAttribute)propInfo.GetCustomAttributes(typeof(TAttribute), inherit).FirstOrDefault();
    }

Upvotes: 3

tvanfosson
tvanfosson

Reputation: 532445

Use the CustomAttributes property on the MemberInfo to get the OrderAttribute and select it's value for the ordering.

var members = myType.GetMembers()
                    .OrderBy(m => m.CustomAttributes
                                   .OfType(typeof(OrderAttribute))
                                   .FirstOrDefault(a => a.Value))

Upvotes: 2

Related Questions