How does Queryable.OfType work?

It is important . The question is not what Queryable.OfType does, it is "how does the code that I see there execute?"

Reflecting Queryable.OfType, I see (after some cleaning):

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 })); } 

So let me see if I have this:

  • Use reflection to get a link to the current method (OfType).
  • Create a new method that is exactly the same, using MakeGenericMethod to change the type parameter of the current method, er, in exactly the same way.
  • The argument of this new method will not be source, but source.Expression. Which is not IQueryable, but we will pass all this to Expression.Call, so OK.
  • A call to Expression.Call, passing null as a method (weird?) To the instance and the cloned method as its arguments.
  • Pass this CreateQuery result and draw a result that seems like the most important part of everything.

The effect of this method now is to return an expression that tells the provider to omit the return values ​​if the type is not equal to TResult or one of its subtypes. But I don’t see how these steps actually achieve this. It seems to create an expression representing a method that returns an IQueryable <TResult>, and makes the body of this method just the whole original expression, not looking at the type. Is the IQueryable provider expected to just keep silent from returning records of a type not selected?

So, are the steps somehow wrong, or am I just not seeing how they lead to the behavior observed at runtime?

+5
linq expression-trees
source share
1 answer

It is not passed to null as a method - it passes it as a "target expression", that is, what it calls the method on. This value is null because OfType is a static method, so it does not need a target.

The call point of MakeGenericMethod is that GetCurrentMethod() returns an open version, i.e. OfType<> instead of OfType<YourType> .

Queryable.OfType itself should not contain any logic to discard any values. This is up to the LINQ provider. The point of Queryable.OfType is to create an expression tree to include the call in OfType , so that when the LINQ provider ultimately needs to convert it to its own format (like SQL), it knows that OfType was called.

This is how Queryable works - basically it allows the provider to see the entire query expression as an expression tree. That's all he wanted to do - when the provider is asked to translate this into real code, that’s where the magic happens.

Queryable could not do the work itself - it has no idea what data the provider stores. How could this OfType with OfType semantics, not knowing if the SQL, LDAP data store or anything else was stored? I agree that it takes some time to get your head around :)

+5
source share

All Articles