Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq Complex OrderBy by Props attributes

I have a class with some props tagged with some attributes. I want to display them on a specific order. So far I can put them in a order, but not on the order that I want.

Here is a simple example of the props with the attributes

[IncludeInEditor]
[IsInPk]
ID
[IncludeInEditor(IsReadOnlyOnModify=true)]
Name
[IncludeInEditor]
Address
[IncludeInEditor]
DOB


The order that I want is:
  1st - Props with IsInPk attribute
  2nd - Props with IncludeInEditor(IsReadOnlyOnModify=true)
  3rd - Props with IncludeInEditor

So far I got this with no sucess and not 100% done (still missing the IsReadOnlyOnModify=true part)

var properties =
item.GetType().GetProperties()
.Where(p => p.GetCustomAttributes(true)
                            .OfType<IncludeInEditorAttribute>()
                            .Count() > 0)
                .Select (x => new 
                {
                    Property = x,
                    Attribute = (IsInPkAttribute)Attribute.GetCustomAttribute(x, typeof(IsInPkAttribute), true) 
                })
                .OrderBy(x => x.Attribute != null ? 1 : -1)
                .Select(x => x.Property)
                .ToArray();
like image 636
2Fast4YouBR Avatar asked Mar 08 '26 18:03

2Fast4YouBR


1 Answers

You can create your own IComparer<T> implementation to compare the attributes on each property:

public class AttributeComparer : IComparer<Attribute>
{
    public int Comparer(Attribute x, Attribute y)
    {
        if(x == null) return y == null ? 0 : -1;
        if(y == null) return 1;

        if(x is IsInPkAttribute) return (y is IsInPkAttribute) ? 0 : 1;
        else if(y is IsInPkAttribute) return -1;
        else
        {
            xa = (IncludeInEditorAttribute)x;
            ya = (IncludeInEditorAttribute)y;

            if(xa.IsReadOnlyOnModify == ya.IsReadOnlyOnModify) return 0;
            else return x.IsReadOnlyOnModify ? 1 : -1;
        }
    }
}

Then your query becomes:

var properties = item.GetType().GetProperties()
    .Where(p => p.GetCustomAttributes(true)
                .OfType<IncludeInEditorAttribute>()
                .Any())
    .Select (x => new 
    {
        Property = x,
        Attribute = Attribute.GetCustomAttribute(x, typeof(IsInPkAttribute), true) ?? Attribute.GetCustomAttribute(x, typeof(IncludeInEditorAttribute, true))
    })
    .OrderBy(x => x.Attribute, new AttributeComparer())
    .Select(x => x.Property)
    .ToArray();
like image 130
Lee Avatar answered Mar 10 '26 08:03

Lee