Sortieren einer Liste mit Lambda/Linq auf Objekte

Ich habe den Namen der "sortieren nach Eigenschaft" in einer Zeichenfolge. Ich werde Lambda/Linq verwenden müssen, um die Liste der Objekte zu sortieren.

Bsp:

public class Employee
{
  public string FirstName {set; get;}
  public string LastName {set; get;}
  public DateTime DOB {set; get;}
}

public void Sort(ref List<Employee> list, string sortBy, string sortDirection)
{
  //Example data:
  //sortBy = "FirstName"
  //sortDirection = "ASC" or "DESC"

  if (sortBy == "FirstName")
  {
    list = list.OrderBy(x => x.FirstName).toList();    
  }

}
  1. Gibt es einen saubereren Weg, die Sortierung durchzuführen, anstatt eine Reihe von ifs zu verwenden, um den Feldnamen zu prüfen (sortBy)?
  2. Kennt die Sortierung den Datentyp?

Eine Sache, die Sie tun könnten, ist Sort so zu ändern, dass es Lambdas besser nutzt.

public enum SortDirection { Ascending, Descending }
public void Sort(ref List list,
                       Func sorter, SortDirection direction)
{
  if (direction == SortDirection.Ascending)
    list = list.OrderBy(sorter);
  else
    list = list.OrderByDescending(sorter);
}

Jetzt können Sie das zu sortierende Feld angeben, wenn Sie die Methode Sort aufrufen.

Sort(ref employees, e => e.DOB, SortDirection.Descending);
Kommentare (7)

Sie können Reflection verwenden, um den Wert der Eigenschaft zu ermitteln.

list = list.OrderBy( x => TypeHelper.GetPropertyValue( x, sortBy ) )
           .ToList();

Wo TypeHelper eine statische Methode hat wie:

public static class TypeHelper
{
    public static object GetPropertyValue( object obj, string name )
    {
        return obj == null ? null : obj.GetType()
                                       .GetProperty( name )
                                       .GetValue( obj, null );
    }
}

Sie könnten auch Dynamic LINQ aus der VS2008 Samples-Bibliothek betrachten. Sie könnten die IEnumerable-Erweiterung verwenden, um die Liste als IQueryable zu casten und dann die Dynamic Link OrderBy-Erweiterung verwenden.

 list = list.AsQueryable().OrderBy( sortBy + " " + sortDirection );
Kommentare (7)

Antwort für 1.:

Sie sollten in der Lage sein, manuell einen Ausdrucksbaum zu erstellen, der an OrderBy übergeben werden kann, indem Sie den Namen als String verwenden. Oder Sie könnten Reflexion verwenden, wie in einer anderen Antwort vorgeschlagen, die weniger Arbeit sein könnte.

Edit: Hier ist ein funktionierendes Beispiel für die manuelle Erstellung eines Ausdrucksbaums. (Sortieren nach X.Value, wenn man nur den Namen "Value" der Eigenschaft kennt). Sie könnten (sollten) eine generische Methode dafür entwickeln.

using System;
using System.Linq;
using System.Linq.Expressions;

class Program
{
    private static readonly Random rand = new Random();
    static void Main(string[] args)
    {
        var randX = from n in Enumerable.Range(0, 100)
                    select new X { Value = rand.Next(1000) };

        ParameterExpression pe = Expression.Parameter(typeof(X), "value");
        var expression = Expression.Property(pe, "Value");
        var exp = Expression.Lambda(expression, pe).Compile();

        foreach (var n in randX.OrderBy(exp))
            Console.WriteLine(n.Value);
    }

    public class X
    {
        public int Value { get; set; }
    }
}

Um einen Ausdrucksbaum zu erstellen, muss man jedoch die beteiligten Typen kennen. Das kann in Ihrem Anwendungsfall ein Problem sein, muss es aber nicht. Wenn Sie nicht wissen, nach welchem Typ Sie sortieren sollen, wird es wahrscheinlich einfacher sein, Reflexion zu verwenden.

Antwort zu 2.:

Ja, da Comparer.Default für den Vergleich verwendet wird, wenn Sie den Comparer nicht explizit definieren.

Kommentare (1)