Важно Вопрос не в том, "Что делает 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 }));
}
Итак, давайте посмотрим, правильно ли я понял:
- Используйте отражение, чтобы получить ссылку на текущий метод (OfType).
- Создайте новый метод, который точно такой же, с помощью MakeGenericMethod, чтобы изменить параметр типа текущего метода, в общем, на то же самое.
- Аргументом для этого нового метода будет не source, а source.Expression. Что не является IQueryable, но мы передадим все это Expression.Call, так что все в порядке.
- Вызовите Expression.Call, передав
null
как метод (странный?) экземпляр и клонированный метод в качестве аргументов.
- Передайте этот результат в CreateQuery и приведите результат, который кажется самой разумной частью всего этого.
Теперь эффект этого метода состоит в том, чтобы возвращать выражение, которое говорит провайдеру, что нужно пропустить возвращение любых значений, где тип не равен TResult или одному из его подтипов. Но я не вижу, как вышеперечисленные шаги действительно достигают этого. Похоже, создается выражение, представляющее метод, который возвращает IQueryable , и тело этого метода просто превращается во все исходное выражение, даже не обращая внимания на тип. Просто ли ожидать, что провайдер IQueryable просто молча не вернет записи не выбранного типа?
Так что вышеперечисленные шаги в некотором смысле неверны, или я просто не вижу, как они приводят к поведению, наблюдаемому во время выполнения?