Где метод ToList()? (IQueryable)

Если я попробую это, он будет работать:

var query = myContextObject.Users.Where(u=>u.Name == "John");
query.ToList();

Я могу вызвать ToList и множество других методов расширения.

Но если я попробую это:

public List ConvertQueryToList(IQueryable query)
{
    return query.ToList();
}

ToList не будет доступным, я предполагаю, что это потому, что ToList - это метод расширения, но тогда как этот ToList прикреплен в первом примере? Возможно ли получить доступ к ToList во втором случае?

Ответ 1

Вам нужно записать его как:

public List<T> ConvertQueryToList<T>(IQueryable<T> query)
{
    return query.ToList();
}

Это приведет к тому, что IQueryable<T> вернет соответствующий List<T>, так как метод Enumerable.ToList() требует ввода IEnumerable<T> в качестве входного (который также работает с IQueryable<T>, поскольку IQueryable<T> наследует IEnumerable<T>).

Таким образом, нет причин использовать его таким образом. Вы всегда можете просто вызвать ToList() напрямую, если вам нужно создать List<T> - абстрагирование внутри второго слоя просто путает API далее.

Если вы пытаетесь преобразовать неосновный интерфейс IQueryable, вам нужно сделать что-то вроде:

public List<T> ConvertQueryToList<T>(IQueryable query)
{
    return query.Cast<T>.ToList();
}

Это потребует вызова типа:

var results = ConvertQueryToList<SomeType>(queryable);

В качестве альтернативы, если вы хотите оставить это не общее (что я бы не рекомендовал), вы можете использовать:

public ArrayList ConvertQueryToList(IQueryable query)
{
    ArrayList results = new ArrayList();
    results.AddRange(query.Cast<object>().ToList());
    return results;
}

Ответ 2

Первый из ваших примеров возвращает IQueryable<T>, тогда как во втором вы используете IQueryable (без параметра Generic Type).

Вы можете проверить два совершенно разных интерфейса здесь и здесь.

Ответ 3

Вот пример расширения для этого:

public static class ListHelper
{
    public static IList ToList(this IQueryable query)
    {
        var genericToList = typeof(Enumerable).GetMethod("ToList")
            .MakeGenericMethod(new Type[] { query.ElementType });
        return (IList)genericToList.Invoke(null, new[] { query });
    }
}