打造自己的LINQ Provider(中):IQueryable和IQueryProvider
摘要:本文为打造自己的LINQ Provider系列文章第二篇,主要详细介绍自定义LINQ Provider中两个最重要的接口IQueryable和IQueryProvider。
[1] IEnumerable[2] IEnumerable
[3] IQueryable
[4] IQueryProvider接口
[5] 扩展LINQ的两种方式
[6] 总结
扩展LINQ的两种方式
通过前面的讲解,我们可以想到,对于LINQ的扩展有两种方式,一是借助于LINQ to Objects,如果我们所做的查询直接在.NET代码中执行,就可以实现IEnumerable<T>接口,而无须再去实现IQueryable并编写自定义的LINQ Provider,如.NET中内置的List<T>等。如我们可以编写一段简单自定义代码:
public class MyData<T> : IEnumerable<T> where T : class { public IEnumerator<T> GetEnumerator() { return null; } IEnumerator IEnumerable.GetEnumerator() { return null; } // 其它成员 }
第二种扩展LINQ的方式当然就是自定义LINQ Provider了,我们需要实现IQueryable<T>和IQueryProvider两个接口,下面先给出一段简单的示意代码,在下一篇中我们将完整的来实现一个LINQ Provider。如下代码所示:
public class QueryableData<TData> : IQueryable<TData> { public QueryableData() { Provider = new TerryQueryProvider(); Expression = Expression.Constant(this); } public QueryableData(TerryQueryProvider provider, Expression expression) { if (provider == null) { throw new ArgumentNullException("provider"); } if (expression == null) { throw new ArgumentNullException("expression"); } if (!typeof(IQueryable<TData>).IsAssignableFrom(expression.Type)) { throw new ArgumentOutOfRangeException("expression"); } Provider = provider; Expression = expression; } public IQueryProvider Provider { get; private set; } public Expression Expression { get; private set; } public Type ElementType { get { return typeof(TData); } } public IEnumerator<TData> GetEnumerator() { return (Provider.Execute<IEnumerable<TData>>(Expression)).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return (Provider.Execute<IEnumerable>(Expression)).GetEnumerator(); } } public class TerryQueryProvider : IQueryProvider { public IQueryable CreateQuery(Expression expression) { Type elementType = TypeSystem.GetElementType(expression.Type); try { return (IQueryable)Activator.CreateInstance( typeof(QueryableData<>).MakeGenericType(elementType), new object[] { this, expression }); } catch { throw new Exception(); } } public IQueryable<TResult> CreateQuery<TResult>(Expression expression) { return new QueryableData<TResult>(this, expression); } public object Execute(Expression expression) { // ...... } public TResult Execute<TResult>(Expression expression) { // ...... } }