比方说,我有一个IQueryable的例子.我怎样才能找到订购的参数? 以下是OrderBy()方法的外观(作为参考): public static IOrderedQueryableT OrderByT, TKey( this IQueryableT source, ExpressionFuncT, TKey keySelector
以下是OrderBy()方法的外观(作为参考):
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) } ) ); }
马特沃伦的暗示:
这不是很好,但它似乎做了这个工作:All queryables (even IOrderedQueryable’s) have expression trees underlying them that encode the activity they represent. You should find using the IQueryable.Expression property a method-call expression node representing a call to the Queryable.OrderBy method with the actual arguments listed. You can decode from the keySelector argument the expression used for ordering. Take a look at the IOrderedQueryable object instance in the debugger to see what I mean.
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 } } }); } }