Lambda/Linq kullanarak bir listeyi nesnelere göre sıralama

Bir dize içinde "sort by özelliğinin" adı var. Nesne listesini sıralamak için Lambda/Linq kullanmam gerekecek.

Ex:

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. Alan adını kontrol etmek için bir grup if kullanmak yerine (sortBy), sıralama yapmanın daha temiz bir yolu var mı
  2. Sıralama veri türünün farkında mı?

Yapabileceğiniz bir şey Sortu lambdaları daha iyi kullanacak şekilde değiştirmektir.

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);
}

Artık Sort yöntemini çağırırken sıralanacak alanı belirtebilirsiniz.

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

Özelliğin değerini almak için Reflection kullanabilirsiniz.

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

TypeHelper'ın aşağıdaki gibi statik bir yöntemi vardır:

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

Ayrıca VS2008 Örnekleri kütüphanesi'deki Dinamik LINQ'ya da bakmak isteyebilirsiniz. Listeyi bir IQueryable olarak dökmek için IEnumerable uzantısını kullanabilir ve ardından Dynamic link OrderBy uzantısını kullanabilirsiniz.

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

1. için cevap:

Adı bir dize olarak kullanarak OrderBy öğesine aktarılabilecek bir ifade ağacını manuel olarak oluşturabilmeniz gerekir. Ya da başka bir yanıtta önerildiği gibi yansıma kullanabilirsiniz, bu daha az uğraştırıcı olabilir.

Edit: İşte manuel olarak bir ifade ağacı oluşturmanın çalışan bir örneği. (Özelliğin yalnızca "Value" adını bilirken X.Value üzerinde sıralama). Bunu yapmak için genel bir yöntem oluşturabilirsiniz (oluşturmalısınız).

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; }
    }
}

Ancak bir ifade ağacı oluşturmak, ilgili türleri bilmenizi gerektirir. Bu, sizin kullanım senaryonuzda bir sorun olabilir ya da olmayabilir. Eğer hangi tipe göre sıralama yapacağınızı bilmiyorsanız, yansıma kullanmak muhtemelen daha kolay olacaktır.

2. için cevap:

Evet, çünkü Comparer.Default, karşılaştırıcıyı açıkça tanımlamazsanız karşılaştırma için kullanılacaktır.

Yorumlar (1)