Подтвердить что ты не робот

Определите, был ли заказан IQueryable <T> или нет.

Есть ли способ узнать, упорядочен ли IQueryable<T> (используя OrderBy или OrderbyDescending)?

Поэтому я знаю, нужно ли называть OrderBy или ThenBy в коллекции.

IQueryable<Contact> contacts = Database.GetContacts();

Я пробовал contacts is IOrderedQueryable<Contact>, но он всегда прав.

Изменить. Я только что изменил свой пример, предыдущий не показывал мою точку зрения. Предположим, что GetContacts использует Entity Framework и просто возвращает все записи таблицы.

Впоследствии я применил несколько функций к contacts, я не знаю, что делают эти функции. Они могут сортировать или фильтровать IQueryable<Contact>.

Когда я верну коллекцию, мне нужно еще раз ее отсортировать. Для этого мне нужно знать, нужно ли мне звонить OrderBy или ThenBy. Поэтому я не переупорядочиваю всю коллекцию, если она уже была отсортирована.

4b9b3361

Ответ 1

Короткий ответ - нет, класс Queryable не поддерживает флаг, или сортировка коллекции не используется, и какой метод мог использоваться для выполнения такого рода.

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

Ответ 2

Это возможно. Здесь используется метод расширения:

public static bool IsOrdered<T>(this IQueryable<T> queryable)
{
    if (queryable == null)
    {
        throw new ArgumentNullException("queryable");
    }

    return queryable.Expression.Type == typeof(IOrderedQueryable<T>);
}

Ответ 3

Да, вы можете проверить дерево 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);

Ответ 4

Вы никогда не узнаете, правильно ли заказаны объекты, если вы не проверите заказ самостоятельно. Ваш пример легко увидеть, что они не упорядочены, потому что числа имеют естественный порядок, но IQueryable является общим, что означает, что он может обрабатывать различные типы объектов. Упорядочение пользовательских объектов (FirstName, LastName, DateStart и LastPayDate) имеет произвольный порядок, и поэтому порядок, в котором они возвращаются, не обязательно является тем заказом, который вы ищете. (Что считается основным полем для сортировки? Это зависит от ваших потребностей.) Поэтому теоретически вопрос "Они заказаны" всегда может быть "Да!". Заказ, который вы ищете, может отличаться от того, что возвращается системе.

Ответ 5

Собственно, вы можете.

Первая проблема, которую я вижу в вашем коде, заключается в том, что вы делаете сборку IQueryable без каких-либо оснований для этого.

Следующий фрагмент:

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

Не нужно даже запускать: первая проверка дает вам предупреждение о времени разработки, в котором говорится, что это выражение никогда не будет истинным.

В любом случае, если вы запустите его, он даст вам False для первой проверки и True для второй проверки.

Вы можете сделать то же самое с IQueryable<T> и IOrderedQueryable<T>, чтобы вы действительно использовали этот тип, и не добавляли в него коллекцию.

Ответ 6

Вы можете проверить ToString() вашего запроса, чтобы узнать, используется ли Order By.

Когда происходит соединение, IQueryable ToString помещает скобки в начало и конец внутреннего запроса. Поэтому, если вы найдете последние закрывающие скобки, вы можете проверить, имеет ли внешний внешний запрос запрос 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;
    }

Я знаю, что он очень грязный, но он работает во всех моих случаях, и я не могу придумать исключительный случай.