确定是否已订购IQueryable

有没有办法知道是否已经订购了IQueryable (使用OrderByOrderbyDescending )?

所以我知道是否在集合上调用OrderByThenBy

 IQueryable contacts = Database.GetContacts(); 

我试过contacts is IOrderedQueryable ,但它总是如此。

编辑 :我刚刚改变了我的例子,前一个并没有真正表明我的观点。 假设GetContacts使用Entity Framework并简单地返回表的所有记录。

稍后,我将几个函数应用于contacts ,我不知道这些函数的作用。 他们可以对IQueryable进行排序或过滤。

当我收回集合时,我需要再次对它进行排序。 为此,我需要知道是否需要调用OrderByThenBy 。 因此,如果已经对整个集合进行了排序,我不会重新排序。

简短的回答是否定的,Queryable类不维护标志或者是否对集合进行了排序,也没有使用什么方法来执行这样的排序。

http://msdn.microsoft.com/en-us/library/system.linq.queryable.aspx

这是可能的。 这是一个扩展方法:

 public static bool IsOrdered(this IQueryable queryable) { if (queryable == null) { throw new ArgumentNullException("queryable"); } return queryable.Expression.Type == typeof(IOrderedQueryable); } 

是的,您可以检查IQueryable.Expression树以查看它是否调用任何OrderBy/ThenBy方法。 可以通过从ExpressionVisitor派生类来检查表达式树。

System.Web有一个内部OrderingMethodFinder – 您可以调整它。 这就是我想出的:

 // Adapted from internal System.Web.Util.OrderingMethodFinder http://referencesource.microsoft.com/#System.Web/Util/OrderingMethodFinder.cs class OrderingMethodFinder : ExpressionVisitor { bool _orderingMethodFound = false; protected override Expression VisitMethodCall(MethodCallExpression node) { var name = node.Method.Name; if (node.Method.DeclaringType == typeof(Queryable) && ( name.StartsWith("OrderBy", StringComparison.Ordinal) || name.StartsWith("ThenBy", StringComparison.Ordinal))) { _orderingMethodFound = true; } return base.VisitMethodCall(node); } public static bool OrderMethodExists(Expression expression) { var visitor = new OrderingMethodFinder(); visitor.Visit(expression); return visitor._orderingMethodFound; } } 

像这样使用它:

 bool isOrdered = OrderingMethodFinder.OrderMethodExists(myQuery.Expression); 

实际上,你可以。

我在你的代码中发现的第一个问题就是你没有任何理由将这个集合转换为IQueryable

以下片段:

 var numbers = new[] {1, 5, 6, 87, 3}; Console.Write(numbers is IOrderedEnumerable); var ordered = numbers.OrderBy(c => c); Console.Write(ordered is IOrderedEnumerable); 

甚至不需要运行:第一次检查会给你一个设计时警告说这个表达式永远不会成立。

无论如何,如果你运行它,它会在第一次检查时给你False,在第二次检查时给你True。

您可以使用IQueryableIOrderedQueryable执行相同的操作,只要您真正使用该类型,而不是将集合转换为它。

除非您自己检查订单,否则您永远不会知道对象是否已正确订购。 您的示例很容易看出它们没有被排序,因为数字具有自然顺序,但IQueryable是通用的,这意味着它可以处理不同类型的对象。 say用户对象(FirstName,LastName,DateStart和LastPayDate)的顺序具有任意顺序,因此返回它们的顺序不一定是您要查找的顺序。 (这被认为是排序的主要领域?这取决于你的需要。)因此,理论上,“他们订购了”这个问题总是“是的!” 您要查找的订单可能与系统返回的订单大不相同。

您可以检查查询的ToString()以查明是否使用了Order By。

当连接发生时,IQueryable的ToString将parantheses放入内部查询的begininng和end。 因此,如果您找到最后一个关闭的parantheses,您可以检查您的最外层查询是否具有Order By子句。

  private bool isOrdered(IQueryable Data) { string query = Data.ToString(); int pIndex = query.LastIndexOf(')'); if (pIndex == -1) pIndex = 0; if (query.IndexOf("ORDER BY", pIndex) != -1) { return true; } return false; } 

我知道它非常脏,但它适用于我的所有情况,我想不出一个例外情况。