Linq 如何从IQueryable对象检索排序信息?

Linq 如何从IQueryable对象检索排序信息?,linq,sorting,expression,iqueryable,Linq,Sorting,Expression,Iqueryable,比如说,我有一个IQueryable的实例。我怎样才能知道它是按哪些参数排序的 以下是OrderBy()方法的外观(作为参考): 公共静态IOrderedQueryable OrderBy( 此IQueryable源、表达式键选择器) { 返回(IOrderedQueryable)source.Provider.CreateQuery( Expression.Call(null, ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMet

比如说,我有一个IQueryable的实例。我怎样才能知道它是按哪些参数排序的

以下是
OrderBy()
方法的外观(作为参考):

公共静态IOrderedQueryable OrderBy(
此IQueryable源、表达式键选择器)
{
返回(IOrderedQueryable)source.Provider.CreateQuery(
Expression.Call(null,
((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(
新类型[]{typeof(T),typeof(TKey)}
),
新表达式[]{source.Expression,Expression.Quote(keySelector)}
)
);
}
马特·沃伦的提示:

所有查询文件(甚至IOrderedQueryable)都有表达式树作为其基础,对它们所表示的活动进行编码。您应该使用IQueryable.Expression属性找到一个方法调用表达式节点,该节点表示对Queryable.OrderBy方法的调用,并列出了实际参数。您可以从KeySelect参数解码用于排序的表达式。看看调试器中的IOrderedQueryable对象实例,了解我的意思


这并不漂亮,但似乎很管用:

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

    }
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用System.Linq;
使用System.Linq.Expressions;
使用System.Windows.Forms;
公开课考试
{
公共INTA;
公共字符串B{get;set;}
公共日期时间C{get;set;}
公共交通工具D;
}
公共类查询项
{
公共查询项(表达式,布尔升序)
{
这个表达式=表达式;
这个。上升=上升;
}
公共表达式{get;private set;}
公共布尔升序{get;私有集;}
公共重写字符串ToString()
{
返回(升序?“asc::“desc:)+表达式;
} 
}
静态类程序
{
公共静态列表GetQueryOrder(表达式)
{
var members=new List();//排队等待轻松下载
GetQueryOrder(表达式,成员,0);
返回成员;
}
静态void GetQueryOrder(表达式表达式、IList成员、int insertPoint)
{
if(expr==null)返回;
开关(扩展节点类型)
{
大小写表达式类型。调用:
var mce=(MethodCallExpression)expr;
如果(mce.Arguments.Count>1)
{//OrderBy etc用arg1表示
开关(mce.Method.Name)
{//note OrderBy[Descending]移动插入点,但随后by[Descending]不移动插入点
案例“OrderBy”://可能会检查MemberInfo
Insert(insertPoint,newQueryOrderItem(mce.Arguments[1],true));
insertPoint=members.Count;//交换顺序以强制执行稳定排序
打破
案例“OrderByDescending”:
Insert(insertPoint,newQueryOrderItem(mce.Arguments[1],false));
insertPoint=members.Count;
打破
案例“ThenBy”:
Insert(insertPoint,newQueryOrderItem(mce.Arguments[1],true));
打破
案例“Thenby Descending”:
Insert(insertPoint,newQueryOrderItem(mce.Arguments[1],false));
打破
}
}
如果(mce.Arguments.Count>0)
{//链接到arg0上
GetQueryOrder(mce.Arguments[0],成员,插入点);
}
打破
}
}
静态void Main()
{
var数据=新[]{
新测试{A=1,B=“abc”,C=DateTime。现在,D=12.3F},
新测试{A=2,B=“abc”,C=DateTime.Today,D=12.3F},
新测试{A=1,B=“def”,C=DateTime.Today,D=10.1F}
}.AsQueryable();
var ordered=(来自数据中的项
orderby item.D降序
按项目排序
orderby item.A降序,item.B
选择项目)。取(20);
//注意:根据“稳定排序”规则,实际上应该对其进行排序
//作为{-A,B,C,-D},因为{-A,B}的最后一个顺序保持不变(在
//a match)前面的排序{C},它依次保留(对于匹配){D}
var members=GetQueryOrder(ordered.Expression);
foreach(成员中的变量项)
{
Console.WriteLine(item.ToString());
}
//用来调查这棵树
TypeDescriptor.AddAttributes(typeof(表达式),新[]{
新的TypeConverterAttribute(typeof(ExpandableObjectConverter))};
Application.Run(新表单
{
控件={
新属性网格{Dock=DockStyle.Fill,SelectedObject=ordered.Expression}
}
});
}
}
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 }
        }
        });

    }
}