zoukankan      html  css  js  c++  java
  • LINQ:创建IQueryable Provider<1>

    这是一个教你创建一个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 IV - Select

    Part V - Improved Column binding

    Part VI - Nested queries

    Part VII - Join and SelectMany

    Part VIII - OrderBy

    Part IX - Removing redundant subqueries

    Part X – GroupBy and Aggregates

    Part XI - More of everything

    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。我们在下一节中再说。
  • 相关阅读:
    一步一步学习Unity3d学习笔记系1.2 单机游戏和网游的数据验证概念
    一步一步学习Unity3d学习笔记系1.1
    Mongodb 官网驱动2.2.4.26版本 增,删 改,查
    使用Zxing 一维码
    Linq 数据排序,分页
    easyui datagrid 批量编辑和提交数据
    Json序列化为对象方法
    百度地图车辆运动轨迹
    GridView后台绑定数据列表方法
    删除重复数据
  • 原文地址:https://www.cnblogs.com/tukzer/p/1805483.html
Copyright © 2011-2022 走看看