Как работает Queryable.OfType? - PullRequest
       36

Как работает Queryable.OfType?

5 голосов
/ 17 сентября 2009

Важно Вопрос не в том, "Что делает Queryable.OfType делает , а в том," как код, который я там вижу, выполняет это? "

Размышляя о Queryable.OfType, я вижу (после некоторой очистки):

    public static IQueryable<TResult> OfType<TResult>(this IQueryable source)
    {
        return (IQueryable<TResult>)source.Provider.CreateQuery(
            Expression.Call(
                null, 
                ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(
                    new Type[] { typeof(TResult) }) ,
                    new Expression[] { source.Expression }));
    }

Итак, давайте посмотрим, правильно ли я понял:

  1. Используйте отражение, чтобы получить ссылку на текущий метод (OfType).
  2. Создайте новый метод, который точно такой же, с помощью MakeGenericMethod, чтобы изменить параметр типа текущего метода, в общем, на то же самое.
  3. Аргументом для этого нового метода будет не source, а source.Expression. Что не является IQueryable, но мы передадим все это Expression.Call, так что все в порядке.
  4. Вызовите Expression.Call, передав null как метод (странный?) экземпляр и клонированный метод в качестве аргументов.
  5. Передайте этот результат в CreateQuery и приведите результат, который кажется самой разумной частью всего этого.

Теперь эффект этого метода состоит в том, чтобы возвращать выражение, которое говорит провайдеру, что нужно пропустить возвращение любых значений, где тип не равен TResult или одному из его подтипов. Но я не вижу, как вышеперечисленные шаги действительно достигают этого. Похоже, создается выражение, представляющее метод, который возвращает IQueryable , и тело этого метода просто превращается во все исходное выражение, даже не обращая внимания на тип. Просто ли ожидать, что провайдер IQueryable просто молча не вернет записи не выбранного типа?

Так что вышеперечисленные шаги в некотором смысле неверны, или я просто не вижу, как они приводят к поведению, наблюдаемому во время выполнения?

1 Ответ

5 голосов
/ 17 сентября 2009

Он не передается в null как метод - он передает его как «целевое выражение», то есть для чего он вызывает метод. Это ноль, потому что OfType является статическим методом, поэтому ему не нужна цель.

Точка вызова MakeGenericMethod заключается в том, что GetCurrentMethod() возвращает открытую версию, т.е. OfType<> вместо OfType<YourType>.

Queryable.OfType само по себе не означает , означающее , чтобы содержать какую-либо логику для исключения возврата любых значений. Это зависит от поставщика LINQ. Смысл Queryable.OfType состоит в том, чтобы создать дерево выражений, включающее в себя вызов OfType, чтобы, когда провайдер LINQ в конечном итоге должен был преобразовать его в свой собственный формат (например, SQL), он знал, что был вызван OfType.

Так работает Queryable в целом - в основном это позволяет провайдеру видеть все выражение запроса в виде дерева выражений. Это все, что он должен делать - когда провайдера просят перевести это в реальный код, это , где происходит волшебство.

Queryable не может выполнить всю работу самостоятельно - он не знает, какое хранилище данных представляет поставщик. Как он мог придумать семантику OfType, не зная, было ли хранилище данных SQL, LDAP или что-то еще? Я согласен, что требуется время, чтобы обдумать:)

...