2010-02-05 7 views
4

예를 들어 IQueryable의 인스턴스가 있습니다. 주문한 매개 변수를 어떻게 알 수 있습니까? 있는 OrderBy() 메소드는 (참고로)처럼 보이는 방법은 다음과IQueryable 객체에서 주문 정보를 검색하는 방법은 무엇입니까?

은 다음과 같습니다

public static IOrderedQueryable<T> OrderBy<T, TKey>(
    this IQueryable<T> source, Expression<Func<T, TKey>> keySelector) 
{ 
    return (IOrderedQueryable<T>)source.Provider.CreateQuery<T>(
     Expression.Call(null, 
      ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(
        new Type[] { typeof(T), typeof(TKey) } 
      ), 
      new Expression[] { source.Expression, Expression.Quote(keySelector) } 
     ) 
    ); 
} 

매트 워렌에서 힌트 :

모든 queryables (심지어 IOrderedQueryable의)는 식 트리가 그들 기초가있다 그들이 나타내는 활동을 인코딩합니다. IQueryable.Expression 속성을 사용하면 실제 인수가 나열된 Queryable.OrderBy 메서드에 대한 호출을 나타내는 메서드 호출 표현식 노드를 찾아야합니다. keySelector 인수에서 순서화에 사용 된 표현식을 디코딩 할 수 있습니다. 디버거의 IOrderedQueryable 객체 인스턴스를보고 무슨 뜻인지 확인하십시오.

답변

4

이 꽤 아니지만, 작업해야 할 것 같다

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Windows.Forms; 

public class Test 
{ 
    public int A; 
    public string B { get; set; } 
    public DateTime C { get; set; } 
    public float D; 
} 
public class QueryOrderItem 
{ 
    public QueryOrderItem(Expression expression, bool ascending) 
    { 
     this.Expression = expression; 
     this.Ascending = ascending; 
    } 
    public Expression Expression { get; private set; } 
    public bool Ascending { get; private set; } 
    public override string ToString() 
    { 
     return (Ascending ? "asc: " : "desc: ") + Expression; 
    } 
} 
static class Program 
{ 

    public static List<QueryOrderItem> GetQueryOrder(Expression expression) 
    { 
     var members = new List<QueryOrderItem>(); // queue for easy FILO 
     GetQueryOrder(expression, members, 0); 
     return members; 
    } 
    static void GetQueryOrder(Expression expr, IList<QueryOrderItem> members, int insertPoint) 
    { 
     if (expr == null) return; 
     switch (expr.NodeType) 
     { 
      case ExpressionType.Call: 
       var mce = (MethodCallExpression)expr; 
       if (mce.Arguments.Count > 1) 
       { // OrderBy etc is expressed in arg1 
        switch (mce.Method.Name) 
        { // note OrderBy[Descending] shifts the insertPoint, but ThenBy[Descending] doesn't 
         case "OrderBy": // could possibly check MemberInfo 
          members.Insert(insertPoint, new QueryOrderItem(mce.Arguments[1], true)); 
          insertPoint = members.Count; // swaps order to enforce stable sort 
          break; 
         case "OrderByDescending": 
          members.Insert(insertPoint, new QueryOrderItem(mce.Arguments[1], false)); 
          insertPoint = members.Count; 
          break; 
         case "ThenBy": 
          members.Insert(insertPoint, new QueryOrderItem(mce.Arguments[1], true)); 
          break; 
         case "ThenByDescending": 
          members.Insert(insertPoint, new QueryOrderItem(mce.Arguments[1], false)); 
          break; 
        } 
       } 
       if (mce.Arguments.Count > 0) 
       { // chained on arg0 
        GetQueryOrder(mce.Arguments[0], members, insertPoint); 
       } 
       break; 
     } 
    } 
    static void Main() 
    { 
     var data = new[] { 
      new Test { A = 1, B = "abc", C = DateTime.Now, D = 12.3F}, 
      new Test { A = 2, B = "abc", C = DateTime.Today, D = 12.3F}, 
      new Test { A = 1, B = "def", C = DateTime.Today, D = 10.1F} 
     }.AsQueryable(); 
     var ordered = (from item in data 
         orderby item.D descending 
         orderby item.C 
         orderby item.A descending, item.B 
         select item).Take(20); 
     // note: under the "stable sort" rules, this should actually be sorted 
     // as {-A, B, C, -D}, since the last order by {-A,B} preserves (in the case of 
     // a match) the preceding sort {C}, which in turn preserves (for matches) {D} 

     var members = GetQueryOrder(ordered.Expression); 
     foreach (var item in members) 
     { 
      Console.WriteLine(item.ToString()); 
     } 

     // used to investigate the tree 
     TypeDescriptor.AddAttributes(typeof(Expression), new[] { 
      new TypeConverterAttribute(typeof(ExpandableObjectConverter)) }); 
     Application.Run(new Form 
     { 
      Controls = { 
      new PropertyGrid { Dock = DockStyle.Fill, SelectedObject = ordered.Expression } 
     } 
     }); 

    } 
} 
관련 문제