Something confusing about IQueryable<T>.GetEnumerator
public class Query<T> : IQueryable<T> ...
{
...
public IEnumerator<T> GetEnumerator()
{
return((IEnumerable<T>)this.provider.Execute(this.expression)).GetEnumerator();
}
}
Query<string> someQuery = new Query<string>();
var results1 = someQuery.Select(...).Where(...);
string[] initialSet = { };
var results2 = initialSet.Select(...).Where(...);
When operating on
initialSet
, Linq-to-object'sWhere<T>
returnsWhereEnumerableIterat开发者_运维知识库or<T>
and thusresults2
is of typeWhereEnumerableIterator<T>
. But when operating onsomeQuery
, doesWhere<T>
operator assign toresults1
an instance retrieved by callingsomeQuery.GetEnumerator
or does it also return some custom class?If the latter, when exactly is
someQuery.GetEnumerator
called byWhere
andSelect
operators?
The type of results2
is just Enumerable<T>
- the type of the implementation that the value of results2
actually refers to at execution time happens to be WhereEnumerableIterator<T>
, that's all.
When operating on someQuery
, it depends what you do with it - the type of the results1
variable is IQueryable<T>
, so you can use more Queryable
calls on it.
someQuery.GetEnumerator()
may never be called - it's up to the query provider implementation to work out exactly how to represent the query; it doesn't need to call GetEnumerator
all the way up the chain like LINQ to Objects typically does.
As for the type of object returned by Queryable.Where
- again, that's up to the query provider implementation - the difference is that whereas the knowledge is baked into Enumerable.Where
and can't be replaced, Queryable.Where
will chain the call through to the query provider.
If the latter, when exactly is someQuery.GetEnumerator called by Where and Select operators?
When the query is enumerated. Hence comes the name.
initialSet.Select(...).Where(...);
This looks wrong. You use the Where to filter, and the Select to project the result. You appear to have it backwards.
精彩评论