Lambda/Linqを使ったオブジェクトへのリストのソート

私は、"sort by property"の名前を文字列で持っています。Lambda/Linqを使ってオブジェクトのリストをソートする必要があります。

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.フィールド名をチェックするために多くのifを使用する(sortBy)代わりに、ソートを行うためのよりクリーンな方法はありますか? 2.sort はデータ型を意識していますか?

ひとつは、Sortを変更して、ラムダをうまく利用することです。

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

これで Sort メソッドを呼び出す際に、ソートするフィールドを指定できるようになりました。

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

Reflectionを使って、プロパティの値を取得することができます。

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

TypeHelperが以下のようなスタティックメソッドを持っているところ。

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

また、VS2008 Samples libraryのDynamic LINQを見てみるのもいいかもしれません。 IEnumerable 拡張を使用して List を IQueryable としてキャストし、Dynamic link OrderBy 拡張を使用することができます。

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

**1.の答え:***。

あなたは、名前を文字列として使用してOrderByに渡すことができる式ツリーを手動で構築することができるはずです。あるいは、他の回答で提案されているようにリフレクションを使用することができ、それはより少ない作業かもしれません。

Edit: ここに手動で式木を構築する作業例があります。(プロパティの名前"Value"しか知らないときに、X.Valueでソートします)。)これを実行するための一般的なメソッドを構築することができます(すべきです)。

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

しかし、式木を構築するには、参加する型を知っている必要があります。それはあなたの使用シナリオでは問題になるかもしれませんし、ならないかもしれません。どの型でソートすべきかわからない場合は、リフレクションを使った方が簡単でしょう。

**2.の答え:***。

はい、Comparer.Defaultが比較のために使用されます。

解説 (1)