When we type the following code
IEnumerable<int> intEnumerable = null;
var q1 = intEnumerable.Where( x => x > 10);
we know that Where method is not part of the IEnumberable<T> interface or IEnumberable interface, it comes from extension method of Enumerable, which is static class and it has no inheritance relation With IEnumerable or IEnumberable<T>. The power of Linq-To-Object does not come from IEnumberable or IEnumberable
public static class Enumerable
{
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
if (predicate == null)
{
throw Error.ArgumentNull("predicate");
}
if (source is Iterator<TSource>)
{
return ((Iterator<TSource>) source).Where(predicate);
}
if (source is TSource[])
{
return new WhereArrayIterator<TSource>((TSource[]) source, predicate);
}
if (source is List<TSource>)
{
return new WhereListIterator<TSource>((List<TSource>) source, predicate);
}
return new WhereEnumerableIterator<TSource>(source, predicate);
}
}
We can see there , the delegate passed in to the method is the code that does the filtering.
IQueryable
public interface IQueryable<T> : IEnumerable<T>, IQueryable, IEnumerable
{}
public interface IQueryable : IEnumerable
{
Type ElementType { get; }
Expression Expression { get; }
IQueryProvider Provider { get; }
}
It does not tell too much? Let's move on an querable example and decomplie to see what it does.
IQueryable<int> intQuerable = null;
var q2 = intQuerable.Where(x => x > 10);
// decomplied by reflector
ParameterExpression CS$0$0000;
IQueryable<int> q2 = intQuerable.Where<int>(Expression.Lambda<Func<int, bool>>(Expression.GreaterThan(CS$0$0000 = Expression.Parameter(typeof(int), "x"), Expression.Constant(10, typeof(int))), new ParameterExpression[] { CS$0$0000 }));
From this example, we can see that the Lamda Expression is not converted to a delegate, but to an expression tree. But why the extension method Enumerable.Where(IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) is not used? It turns out that, the c# compiler pick a more a suitable extension from Queryable. Here is the code from Reflector.
public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
if (predicate == null)
{
throw Error.ArgumentNull("predicate");
}
return source.Provider.CreateQuery<TSource>(Expression.Call(null, ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(new Type[] { typeof(TSource) }), new Expression[] { source.Expression, Expression.Quote(predicate) }));
}
Unlike the Enumerable.Where methhod, this method does not have a delegate to do the filtering. And also the expression can not do the filtering either, it is the IQuerable.Provider which does the filtering. The provider takes the expression tree and does filtering later by converting expression tree to provider specific algorithm like TSQL.
IEumberable<T> is very easy to implement, in fact all the collection they are IEnumberable<T*gt;. Iterator makes it even easier. So there is not such thing as implementing a IEnumberableProvider, because the delegate does the query. But to implement IQueryable is more difficult, because expression does not query. It is IQueryProvider does the job. You need to implement IQuerableProvider
public interface IQueryProvider
{
IQueryable CreateQuery(Expression expression);
IQueryable<TElement> CreateQuery<TElement>(Expression expression);
object Execute(Expression expression);
TResult Execute<TResult>(Expression expression);
}
No comments:
Post a Comment