这是一个教你创建一个LINQ IQueryable Provider的系列教程,总共13篇,来源于The Wayward WebLog,翻译中除去了一部分作者的琐碎之语,如有翻译不当之处,请指出,谢谢!
系列索引:
Part I - Reusable IQueryable base classes
Part II - Where and reusable Expression tree visitor
Part II - Local variable references
Part V - Improved Column binding
Part VII - Join and SelectMany
Part IX - Removing redundant subqueries
Part X – GroupBy and Aggregates
Part XII - Relationships and the IQ Toolkit
Part XIII - Updates and Batch Processing
Part XIV - Mapping and Providers
Part XV - Transactions, Sessions and Factories
Part XVI - Performance and Caching
Part XVII - Automatic Caching and Loading Policies
现在你可以通过CodePlex上查看这个项目。
http://www.codeplex.com/IQToolkit
balabalbala。。。
首先提示大家IQueryable接口在LINQ Beta2中发生了变化,从单接口IQueryable分解为两个:IQueryable和IQueryProvider。我们先粗略过一下这些知识。
如果你使用Visual Studio “转到定义”功能,你就可以看到这些东西:
public interface IQueryable : IEnumerable { Type ElementType { get; } Expression Expression { get; } IQueryProvider Provider { get; } } public interface IQueryable<T> : IEnumerable<T>, IQueryable, IEnumerable { }
(balabala:IQueryable本来很有料,但是现在里面的好东西全部被拆分到IQueryProvider中去了,想当年我开始研究LINQ的时候,这个类还是很值得一看的。)
IQueryable接口中包含了三个只读的属性:
- ElementType:指示元素类型(在IQueryable<T>中也是);
注意:所有实现IQueryable接口的类都必须实现IQueryable<T>.IQueryable<T>将会使用的更多,非泛型实现只是用来提供一种创建dynamic query时的弱类型入口。如果你更深入的研究下IQueryable基础实现(System.Linq.Queryable),你会发现它只不过是是一种自动构建ExpressionTree的机制。
- Expression:
IQueryable接口典型的要素,包含着一个由LINQ查询操作符和函数调用组成的树形结构。
使用Queryable.Where方法,就是在IQueryable的表达式顶端添加一个函数调用ExpressionNode,最终仍返回其本身。
- Provider: 返回IQueryProvider的实例。
public interface IQueryProvider { IQueryable CreateQuery(Expression expression); IQueryable<TElement> CreateQuery<TElement>(Expression expression); object Execute(Expression expression); TResult Execute<TResult>(Expression expression); }
看到这个接口你可以看到它实际上只有两个操作符:CreateQuery和Execute,只不过提供了泛型和非泛型两种实现。
CreateQuery方法通过特定的ExpressionTree创建一个新的IQueryable查询实例。
Execute方法是真正执行查询表达式的Provider的入口。
通过IQueryable和IQueryProvider分离的方式,我们可以只需要实现一个IQueryable,并且在任何Provider中使用。我们先创建一个实现IQueryable<T>和其他必须接口的类Query<T>。
public class Query<T> : IQueryable<T>, IQueryable, IEnumerable<T>, IEnumerable, IOrderedQueryable<T>, IOrderedQueryable { QueryProvider provider; Expression expression; public Query(QueryProvider provider) { if (provider == null) { throw new ArgumentNullException("provider"); } this.provider = provider; this.expression = Expression.Constant(this); } public Query(QueryProvider provider, Expression expression) { if (provider == null) { throw new ArgumentNullException("provider"); } if (expression == null) { throw new ArgumentNullException("expression"); } if (!typeof(IQueryable<T>).IsAssignableFrom(expression.Type)) { throw new ArgumentOutOfRangeException("expression"); } this.provider = provider; this.expression = expression; } Expression IQueryable.Expression { get { return this.expression; } } Type IQueryable.ElementType { get { return typeof(T); } } IQueryProvider IQueryable.Provider { get { return this.provider; } } public IEnumerator<T> GetEnumerator() { return ((IEnumerable<T>)this.provider.Execute(this.expression)).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this.provider.Execute(this.expression)).GetEnumerator(); } public override string ToString() { return this.provider.GetQueryText(this.expression); } } IQueryable实现很浅显,仅仅是持有一个Expression Tree和Provider。
接下来我们提供一些Provider的实现,我先实现一个抽象基类,真正的Provider都可以从这个类派生而来。
public abstract class QueryProvider : IQueryProvider { protected QueryProvider() { } IQueryable<S> IQueryProvider.CreateQuery<S>(Expression expression) { return new Query<S>(this, expression); } IQueryable IQueryProvider.CreateQuery(Expression expression) { Type elementType = TypeSystem.GetElementType(expression.Type); try { return (IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(elementType), new object[] { this, expression }); } catch (TargetInvocationException tie) { throw tie.InnerException; } } S IQueryProvider.Execute<S>(Expression expression) { return (S)this.Execute(expression); } object IQueryProvider.Execute(Expression expression) { return this.Execute(expression); } public abstract string GetQueryText(Expression expression); public abstract object Execute(Expression expression); }
还有一个辅助类:
internal static class TypeSystem { internal static Type GetElementType(Type seqType) { Type ienum = FindIEnumerable(seqType); if (ienum == null) return seqType; return ienum.GetGenericArguments()[0]; } private static Type FindIEnumerable(Type seqType) { if (seqType == null || seqType == typeof(string)) return null; if (seqType.IsArray) return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType()); if (seqType.IsGenericType) { foreach (Type arg in seqType.GetGenericArguments()) { Type ienum = typeof(IEnumerable<>).MakeGenericType(arg); if (ienum.IsAssignableFrom(seqType)) { return ienum; } } } Type[] ifaces = seqType.GetInterfaces(); if (ifaces != null && ifaces.Length > 0) { foreach (Type iface in ifaces) { Type ienum = FindIEnumerable(iface); if (ienum != null) return ienum; } } if (seqType.BaseType != null && seqType.BaseType != typeof(object)) { return FindIEnumerable(seqType.BaseType); } return null; } }
真正的动作在Execute中执行,只有在这里才会执行Expression Tree。我们在下一节中再说。