Y2theZ
Y2theZ

Reputation: 10402

LINQ: Sort a list depending on parameter

I have a LINQ to object query to select all the persons that are above 20 years old

IEnumerable<Object> result = null;
result = (from person in AllPersons.ToList()
          where  person.age > 20
                  select new
                  {
                      FirstName= person.FirstName,
                      LastName= person.LastName,
                      Email= person.Email,
                      PhoneNumber= person.PhoneNumber


                  });
return result;

I have a parameter string SortProperty I want to use to sort the result based on the property.

So for example if SortProperty="FirstName" I want to sort the result based on the first name.

I tried to do the following:

return result.OrderBy(x => x.GetType().GetProperty(SortProperty));

but it did not work

any idea how to do it?

PS: I don't want to test all the possibilities, and do a if-else on each, or a case switch. I'm looking for an efficient way to do this

Thanks

Upvotes: 1

Views: 5927

Answers (4)

Petar Petrov
Petar Petrov

Reputation: 2869

I'm using something like this :

var sortExpression = @"A,C";
var expressions = sortExpression.Split(new[] { ',' });

var cmpPredicates = new Dictionary<string, Func<Person, Person, int>>(3);
cmpPredicates.Add(@"A", (x, y) => x.A.CompareTo(y.A));
cmpPredicates.Add(@"B", (x, y) => x.B.CompareTo(y.B));
cmpPredicates.Add(@"C", (x, y) => x.C.CompareTo(y.C));
cmpPredicates.Add(@"Default", (x, y) => x.Id.CompareTo(y.Id));

var currentPredicates = new Func<Person, Person, int>[expressions.Length + 1];
for (int i = 0; i < expressions.Length; i++)
{
    currentPredicates[i] = cmpPredicates[expressions[i]];
}
// Default sort order
currentPredicates[currentPredicates.Length - 1] = cmpPredicates[@"Default"];

persons.Sort((x, y) =>
                {
                    var cmp = 0;

                    var index = 0;
                    while (cmp == 0 && index < currentPredicates.Length)
                    {
                        cmp = currentPredicates[index++](x, y);
                    }

                    return cmp;
                });

where the Person class has the following definition

public class Person
    {
        public string A { get; set; }
        public string B { get; set; }
        public string C { get; set; }

        public long Id { get; set; }

        public Person()
        {
            this.A = string.Empty;
            this.B = string.Empty;
            this.C = string.Empty;
        }
    }

The main benefit is the multiproperty support. With additional checks(duplicates & exist & predicate limit) is can be user provided.

Upvotes: 0

Blablablaster
Blablablaster

Reputation: 3348

Try

return result.OrderBy(x => x.GetType().GetProperty(SortProperty).GetValue(x, null));

Upvotes: 1

Parv Sharma
Parv Sharma

Reputation: 12705

return result.OrderBy( x => TypeHelper.GetPropertyValue( x, sortProperty ) )
           .ToList();

Upvotes: 0

Eoin Campbell
Eoin Campbell

Reputation: 44268

Check out the Dynamic Linq Extensions Libraries...

It has extension Methods which accept strings instead of Properties.

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Since your SortProperty is already a string you could do

var result = (from person in AllPersons.ToList()
              where  person.age > 20
              select new
                     {
                        FirstName= person.FirstName,
                        LastName= person.LastName,
                        Email= person.Email,
                        PhoneNumber= person.PhoneNumber
                     }
              ).OrderBy(SortProperty);

return result;

Also, depending on what AllPersons is, it might not make sense to Enumerate that by calling ToList() until the end. e.g.

var result = (from person in AllPersons
             ...
             ).OrderBy(SortProperty).ToList();

Upvotes: 2

Related Questions