Linq 如何从IQueryable对象检索排序信息?
比如说,我有一个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
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 }
}
});
}
}