Importante La pregunta no es "¿Qué hacer Queryable.OfType , es '¿cómo el código veo que hay que cumplir'¿Cómo funciona Queryable.OfType?
Reflexionando sobre Queryable.OfType, veo (después de algo de limpieza)?:
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 }));
}
Así que vamos a ver si lo he entendido bien:.
- utilizar la reflexión para tomar una referencia al método actual (OfType)
- Haz un nuevo método, que es exactamente el mismo, usando MakeGenericMethod para cambiar el parámetro de tipo del método actual a, er, exactamente la misma cosa.
- El argumento para ese nuevo método no será source, sino source.Expression. Lo cual no es un IQueryable, pero le pasaremos todo a Expression. Llama, así que está bien.
- llamada Expression.Call, pasando
null
comométodo (raro?)ejemplo y el método clonado como sus argumentos. - Pase ese resultado a CreateQuery y emita el resultado, que parece ser la parte más sana de todo el asunto.
Ahora el efecto de este método es devolver una expresión que indica al proveedor omitir devolver cualquier valor en el que el tipo no es igual a TResult o uno de sus subtipos. Pero no puedo ver cómo los pasos anteriores realmente logran esto. Parece que está creando una expresión que representa un método que devuelve IQueryable <TResult>, y convierte el cuerpo de ese método simplemente en la expresión de origen completa, sin siquiera mirar el tipo. ¿Se espera simplemente que un proveedor de IQueryable silenciosamente no devuelva ningún registro que no sea del tipo seleccionado?
¿Los pasos anteriores son incorrectos de alguna manera o simplemente no veo cómo resultan en el comportamiento observado en el tiempo de ejecución?
OK, ¿lo tengo claro? 1. La llamada a MakeGenericMethod es necesaria porque puede pasar una versión abierta de OfType, con un argumento de YourType (por separado), pero no puede pasar OfType como un argumento. Esa parte al menos tiene sentido. 2. El objetivo de todo esto es simplemente decirle al proveedor "ir a implementar OfType" en lugar de producir una expresión de una implementación de OfType. Continúa en el siguiente comentario ... –
Sin embargo, no puede simplemente devolver algo similar a Expression.OfType (lo que esperaría, según su explicación) porque eso realmente no existe. Entonces, en su lugar, devuelve algo que equivale a lo mismo, solo que se implementa de manera diferente por alguna razón. –
No, devuelve algo que representa una llamada a 'Queryable.OfType', al igual que' Select' devuelve un 'IQueryable' que representa la consulta anterior con una llamada encadenada a 'Queryable.Select', etc. No es un * expresión * de 'OfType', es una expresión que representa una * llamada * a' OfType'. –