2013-01-12 11 views
7

ソート用の式を作成しようとしています.1つのプロパティを使用してリストをソートするコードを記述しました。複数のソートを含む式を構築する

しかし、私は最初に1つのプロパティでソートする必要があります。次に2番目に別のプロパティなどでソートする必要があります。

私は、そのようなものを実装する式を作成したいと言っています:students.OrderBy(fistExpression.Compile()).ThenBy(secondImpression.Complie()).ThenBy(thirdExpression.Compile())

どのように動的にそのThenByメソッドを配置しますか?

Type studentType = typeof(Student); 
ParameterExpression studentParam = Expression.Parameter(studentType, "x"); 
MemberInfo ageProperty = studentType.GetProperty("Age"); 
MemberExpression valueInNameProperty = 
    Expression.MakeMemberAccess(studentParam, ageProperty); 
Expression<Func<Student, int>> orderByExpression = 
    Expression<Func<Student, int>>.Lambda<Func<Student, int>>(valueInNameProperty, studentParam); 
var sortedStudents = students.OrderBy(orderByExpression.Compile()); 
+0

明確にするために、一連の式を.OrderByと.ThenBy、coに渡すという機能を複製する.OrderByに渡すことができる単一の式を作成する方法を探しています起立? –

+0

Dupe http://stackoverflow.com/questions/41244/dynamic-linq-orderby – aquinas

答えて

2

マイソリューション:あなたの表情構成コードで

public static Func<Student, object> BuildPredicate(string propertyName) 
{ 
    Type studentType = typeof(Student); 
    ParameterExpression studentParam = Expression.Parameter(studentType, "x"); 
    MemberInfo ageProperty = studentType.GetProperty(propertyName); 
    MemberExpression valueInNameProperty = Expression.MakeMemberAccess(studentParam, ageProperty); 
    UnaryExpression expression = Expression.Convert(valueInNameProperty, typeof (object)); 
    Expression<Func<Student, object>> orderByExpression = Expression.Lambda<Func<Student, object>>(expression, studentParam); 
    return orderByExpression.Compile(); 
} 

objectにキャスト追加され

は、ここに私のコードです。

var sortedStudents = students.OrderBy(BuildPredicate("Age")); 
foreach (var property in typeof(Student).GetProperties().Where(x => !String.Equals(x.Name, "Age"))) 
{ 
    sortedStudents = sortedStudents.ThenBy(BuildPredicate(property.Name)); 
} 

var result = sortedStudents.ToList(); 

最後に、Studentサンプルクラス:

public class Student 
{ 
    public int Age { get; set; } 
    public string Name { get; set; } 
} 

更新:

別のアプローチをマークする属性を使用しているあなたはThenByのチェーンを作成する方法である

あなたのStudentの特典をで使用するおよびThenBy。同様に:あなたはUseInOrderByAttributeを使用してソートチェーンを構築することができる方法である

public class Student 
{ 
    [UseInOrderBy] 
    public int Age { get; set; } 

    [UseInOrderBy(Order = 1)] 
    public string Name { get; set; } 
} 

[AttributeUsage(AttributeTargets.Property)] 
internal class UseInOrderByAttribute : Attribute 
{ 
    public int Order { get; set; } 
} 

Type studentType = typeof (Student); 
var properties = studentType.GetProperties() 
          .Select(x => new { Property = x, OrderAttribute = x.GetCustomAttribute<UseInOrderByAttribute>() }) 
          .Where(x => x.OrderAttribute != null) 
          .OrderBy(x => x.OrderAttribute.Order); 

var orderByProperty = properties.FirstOrDefault(x => x.OrderAttribute.Order == 0); 
if (orderByProperty == null) 
    throw new Exception(""); 

var sortedStudents = students.OrderBy(BuildPredicate(orderByProperty.Property.Name)); 
foreach (var property in properties.Where(x => x.Property.Name != orderByProperty.Property.Name)) 
{ 
    sortedStudents = sortedStudents.ThenBy(BuildPredicate(property.Property.Name)); 
} 

var result = sortedStudents.ToList(); 

を修正:BuildPredicatedynamicずに書かことができます。 BuildPredicateサンプルコードが変更されました。

1

ソートできるようにするプライベートプロパティがあるとします。 あなたは、たとえば、このクラスを使用している場合:

public class Student 
{ 
    public Student (int age, string name) 
    { 
     Age = age; 
     Name = name; 
    } 

    private string Name { get; set; } 

    public int Age { get; set; } 

    public override string ToString() 
    { 
     return string.Format ("[Student: Age={0}, Name={1}]", Age, Name); 
    } 
} 

あなたは、パブリックとプライベートの両方の性質を取得する式を作成するには、次のメソッドを使用することができます。使用方法の

public static Func<TType, TResult> CreateExpression<TType, TResult>(string propertyName) 
{ 
    Type type = typeof(TType); 
    ParameterExpression parameterExpression = Expression.Parameter(type, propertyName); 
    MemberInfo property = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); 
    MemberExpression valueInProperty = Expression.MakeMemberAccess(parameterExpression, property); 

    return Expression.Lambda<Func<TType,TResult>>(valueInProperty, parameterExpression).Compile(); 
} 

例:

 var students = new [] { 
      new Student(20, "Ben"), 
      new Student(20, "Ceasar"), 
      new Student(20, "Adam"), 
      new Student(21, "Adam"), 
     }; 

     var sortedStudents = students 
      .OrderBy(CreateExpression<Student, string>("Name")) 
      .ThenBy(CreateExpression<Student, int>("Age")); 

     sortedStudents.ToList().ForEach(student => Console.WriteLine(student)); 
     /* 
     Prints: 
     [Student: Age=20, Name=Adam] 
     [Student: Age=21, Name=Adam] 
     [Student: Age=20, Name=Ben] 
     [Student: Age=20, Name=Ceasar] 
     */ 
関連する問題