关于linq中Enumerable类和Queryable类的差别

baysos 2014-12-11 04:31:00
加精
我们都知道在linq中的两个核心Enumerable类和Queryable类,这两个类拥有几乎完全相同方法签名的方法组,
不同的是一个是用IEnumerable做参数,一个是IQueryable做参数,而在Queryable类中将所有FUNC<>委托都用Expression表达式包了一次。
我还知道的是Enumerable类主要是应用于Linq to object,即对于内存中的对象查询以IEnumerable对象为主,查询是面向集合类的;而Queryable是针对于自定义数据源的,比如linq to sql,linq to xml。
虽然说是这么说,但是我对于这样区分的动机和概念还是有点模糊,那么他们在相对底层的实现上具体有什么差别呢?我们又该怎样很好的区分这两个类来做扩展之类的编码?
...全文
4321 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
mOtt1 2018-06-30
  • 打赏
  • 举报
回复
看了之后感觉更迷了
编程程编 2017-03-23
  • 打赏
  • 举报
回复
引用 7 楼 caozhy 的回复:
再给一个LINQ Provider的例子
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var query = from x in new Integers()
                        where x < 10
                        select x;
            foreach (var item in query)
                Console.WriteLine(item);
            var query1 = from x in new Integers().AsEnumerable()
                         where x < 10
                         select x;
            foreach (var item in query1)
                Console.WriteLine(item);
        }
    }

    class Integers : IQueryable<int>
    {
        private LinqToIntegerProvider provider;

        private Expression expression;

        public Integers()
        {
            provider = new LinqToIntegerProvider();
            expression = Expression.Constant(this);
        }

        public Integers(LinqToIntegerProvider p, Expression ex)
        {
            provider = p;
            expression = ex;
        }

        public IEnumerator<int> GetEnumerator()
        {
            return (provider.Execute<IEnumerable<int>>(Expression)).GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }

        public Type ElementType
        {
            get { return typeof(int); }
        }

        public Expression Expression
        {
            get { return expression; }
        }

        public IQueryProvider Provider
        {
            get { return provider; }
        }
    }

    class LinqToIntegerProvider : IQueryProvider
    {
        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            return new Integers(this, expression) as IQueryable<TElement>;

        }

        public IQueryable CreateQuery(Expression expression)
        {
            throw new NotImplementedException();            
        }

        public TResult Execute<TResult>(Expression expression)
        {
            string s = expression.ToString();
            if (s.Contains("Where"))
            {
                string max = Regex.Match(s, @"x\s<\s(\d+)").Groups[1].Value;
                return (TResult)foo(int.Parse(max));
            }
            else
            {
                return (TResult)foo(int.MaxValue);
            }

        }

        private IEnumerable<int> foo(int max)
        {
            for (int i = 0; i < max; i++)
                yield return i;
        }

        public object Execute(Expression expression)
        {
            throw new NotImplementedException();
        }
    }
}
当然,我省略了Provider解析表达式树的过程,我硬编码地视作where x < 某个值。 你可以对比下AsEnumerable和不加有什么区别,后者执行的是LINQ TO OBJECTS
感谢前辈,让我对这两个接口有更深的理解了,虽然还有很多东西不明白 但是这个代码真的很助于理解。直接打一遍Debug一下 就能懂个七七八八,感谢
kisskk2010 2014-12-27
  • 打赏
  • 举报
回复
看完高手解答,感觉更深奥
  • 打赏
  • 举报
回复
linq也是属于反人类语言的一种。
我现在在路上 2014-12-16
  • 打赏
  • 举报
回复
额,强大 学习
ouyang4683 2014-12-16
  • 打赏
  • 举报
回复
看完高手解答,感觉更深奥了
  • 打赏
  • 举报
回复
l2999019 2014-12-15
  • 打赏
  • 举报
回复
学习了。
smthgdin_020 2014-12-12
  • 打赏
  • 举报
回复
虽然命名和用法看起来一样,但是一个是委托一个是表达式树。
aday 2014-12-12
  • 打赏
  • 举报
回复
这篇帖子非常好! 在做Silverlight系统的时候,服务器端是IQueryable,客户端是IEnumerable,我想这是不是更好的解释了一个是面向数据,一个是面向内存?
  • 打赏
  • 举报
回复
严重学习
by_封爱 版主 2014-12-12
  • 打赏
  • 举报
回复
不明觉厉
ni198987hao 2014-12-12
  • 打赏
  • 举报
回复
太深奥了。。。难懂
BestSmiles 2014-12-12
  • 打赏
  • 举报
回复
引用 1 楼 sp1234 的回复:
我们使用 linq to object 时一非常注重性能,因为毕竟是直接操作内存中的大量数据。 而使用linq provider 时因为面向“跨进程通讯”这一个层次,所以对上述要求就差一些,重点转移为:它能不能方便、高效地编译为(数据库的)原生查询语言。
无语
threenewbee 2014-12-12
  • 打赏
  • 举报
回复
引用 20 楼 baysos 的回复:
恩,我还得再仔细消化一下……
看我的代码 在Linq to Objects中
        public static IEnumerable<T> Where<T>(this IEnumerable<T> data, Func<T, bool> predicate)
        {
            Console.WriteLine("where");
            foreach (T item in data)
                if (predicate(item)) yield return item;
        }
predicate已经编译为本地代码了,这个函数只能调用它,但是不能知道这个条件是什么,不能获取到"<10"这个条件。 对照看
        public TResult Execute<TResult>(Expression expression)
        {
            string s = expression.ToString();
            if (s.Contains("Where"))
            {
                string max = Regex.Match(s, @"x\s<\s(\d+)").Groups[1].Value;
                return (TResult)foo(int.Parse(max));
            }
            else
            {
                return (TResult)foo(int.MaxValue);
            }
 
        }
很明显,这里可以得到这个查询条件,可以知道这个 < 10。
baysos 2014-12-12
  • 打赏
  • 举报
回复
恩,我还得再仔细消化一下……
conversion1990 2014-12-11
  • 打赏
  • 举报
回复
t太深奥了。。。难懂
threenewbee 2014-12-11
  • 打赏
  • 举报
回复
总之,无论是Linq to Objects还是Linq Provider都没有什么神秘,都可以用几行代码实现。 我想你自己都能实现了,还有什么不理解的么?
threenewbee 2014-12-11
  • 打赏
  • 举报
回复
再给一个LINQ Provider的例子
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var query = from x in new Integers()
                        where x < 10
                        select x;
            foreach (var item in query)
                Console.WriteLine(item);
            var query1 = from x in new Integers().AsEnumerable()
                         where x < 10
                         select x;
            foreach (var item in query1)
                Console.WriteLine(item);
        }
    }

    class Integers : IQueryable<int>
    {
        private LinqToIntegerProvider provider;

        private Expression expression;

        public Integers()
        {
            provider = new LinqToIntegerProvider();
            expression = Expression.Constant(this);
        }

        public Integers(LinqToIntegerProvider p, Expression ex)
        {
            provider = p;
            expression = ex;
        }

        public IEnumerator<int> GetEnumerator()
        {
            return (provider.Execute<IEnumerable<int>>(Expression)).GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }

        public Type ElementType
        {
            get { return typeof(int); }
        }

        public Expression Expression
        {
            get { return expression; }
        }

        public IQueryProvider Provider
        {
            get { return provider; }
        }
    }

    class LinqToIntegerProvider : IQueryProvider
    {
        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            return new Integers(this, expression) as IQueryable<TElement>;

        }

        public IQueryable CreateQuery(Expression expression)
        {
            throw new NotImplementedException();            
        }

        public TResult Execute<TResult>(Expression expression)
        {
            string s = expression.ToString();
            if (s.Contains("Where"))
            {
                string max = Regex.Match(s, @"x\s<\s(\d+)").Groups[1].Value;
                return (TResult)foo(int.Parse(max));
            }
            else
            {
                return (TResult)foo(int.MaxValue);
            }

        }

        private IEnumerable<int> foo(int max)
        {
            for (int i = 0; i < max; i++)
                yield return i;
        }

        public object Execute(Expression expression)
        {
            throw new NotImplementedException();
        }
    }
}
当然,我省略了Provider解析表达式树的过程,我硬编码地视作where x < 某个值。 你可以对比下AsEnumerable和不加有什么区别,后者执行的是LINQ TO OBJECTS
threenewbee 2014-12-11
  • 打赏
  • 举报
回复
不用讲原理,直接上代码 你知道其实LINQ TO OBJECTS和LINQ TO XXX都可以自己实现么? 我们先实现一个L2O,注意,我们注释掉using System.Linq;并且自己写两个方法Where和Select
using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var query = from x in new int[] { 1, 2, 3, 4, 5 }
                        where x > 3
                        select x.ToString();
            foreach (var item in query)
                Console.WriteLine(item);
        }
    }

    static class MyLinq
    {
        public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> data, Func<TSource, TResult> selector)
        {
            Console.WriteLine("select");
            foreach (TSource item in data)
                yield return selector(item);
        }

        public static IEnumerable<T> Where<T>(this IEnumerable<T> data, Func<T, bool> predicate)
        {
            Console.WriteLine("where");
            foreach (T item in data)
                if (predicate(item)) yield return item;
        }
    }
}
运行 select where 4 5 Press any key to continue . . .
加载更多回复(5)
目录 1 LINQ查询结果集 1 2 System.Array 数组 1 2.1 基于System.Array定义数组 1 2.2 基于型定义数组 1 2.3 数组元素的清空 1 2.4 System.Array静态成员 1 2.5 不用循环填充数组 1 2.6 数组实例成员 2 3 System.Collections 集合 2 3.1 ArrayList 2 3.1.1 实例成员 2 3.1.2 静态成员 2 3.2 List 3 3.3 Hashtable 6 3.4 SortedList 6 3.5 SortedList 7 3.6 Queue 8 3.7 Stack 8 3.8 LinkedList 8 3.9 HashSet 9 4 System.Linq 10 4.1 System.Linq.Enumerable 10 4.2 System.Linq.Queryable 10 4.3 System.Linq.Lookup 10 4.4 System.Linq.Expressions.Expression 10 5 接口 10 5.1 IEnumerable 、IEnumerator 10 5.1.1 正常使用 10 5.1.2 C#的 yield 12 5.2 IEnumerable 12 5.3 IEnumerator 12 5.4 ICollection 12 5.5 ICollection 13 5.6 IList 13 5.7 IList 13 5.8 IEqualityComparer 13 5.9 IEqualityComparer 13 5.10 IDictionary 13 5.11 IDictionary 13 5.12 IDictionaryEnumerator 13 5.13 IComparer 13 5.13.1 接口方法说明 int Compare(object x, object y) 13 5.13.2 ArrayList.Sort (IComparer) 方法 13 5.14 IComparer 14 5.14.1 接口方法override int Compare(T x, T y)说明 14 5.14.2 List.Sort (IComparer) 方法 14 5.15 System.Linq.IGrouping 14 5.16 System.Linq.ILookup 14 5.17 System.Linq.IOrderedEnumerable 14 5.18 System.Linq.IOrderedQueryable 14 5.19 System.Linq.IOrderedQueryable 15 5.20 System.Linq.IQueryable 15 5.21 System.Linq.IQueryable 15 5.22 System.Linq.IQueryProvider 15 6 集合扩展方法 15 6.1 集合扩展方法的实现:一个Where的例子 15 6.2 延迟 15 6.2.1 Select 选择 16 6.2.2 SelectMany 选择 16 6.2.3 Where 条件 16 6.2.4 OrderBy 排序升 17 6.2.5 OrderByDescending 排序降 17 6.2.6 GroupBy 分组 17 6.2.7 Join 联合查询 18 6.2.8 GroupJoin 18 6.2.9 Take 获取集合的前n个元素 19 6.2.10 Skip 跳过集合的前n个元素 19 6.2.11 Distinct 过滤集合的相同项 19 6.2.12 Union 连接不同集合,自动过滤相同项 19 6.2.13 Concat 连接不同集合,不会自动过滤相同项 19 6.2.14 Intersect 获取不同集合的相同项(交集) 20 6.2.15 Except 从某集合删除其与另一个集合相同的项 20 6.2.16 Reverse 反转集合 20 6.2.17 TakeWhile 条件第一次不成立就跳出循环 20 6.2.18 SkipWhile 条件第一次不成立就失效,将后面的数据全取 20 6.2.19 Cast 将集合转换为强型集合 21 6.2.20 OfType 过滤集合的指定型 21 6.3 不延迟(浅复本) 21 6.3.1 Single 集合符合条件的唯一元素,浅复本 21 6.3.2 SingleOrDefault 集合符合条件的唯一元素(没有则返回型默认值),浅复本 21 6.3.3 First 集合的第一个元素,浅复本 21 6.3.4 FirstOrDefault 集合的第一个元素(没有则返回型默认值),浅复本 22 6.3.5 Last 集合的最后一个元素,浅复本 22 6.3.6 LastOrDefault 集合的最后一个元素(没有则返回型默认值),浅复本 22 6.3.7 ElementAt 集合指定索引的元素,浅复本 22 6.3.8 ElementAtOrDefault 集合指定索引的元素(没有则返回型默认值),浅复本 22 6.3.9 Contains 判断集合是否包含有某一元素 22 6.3.10 Any 判断集合是否有元素满足某一条件 22 6.3.11 All 判断集合是否所有元素都满足某一条件 23 6.3.12 SequenceEqual 判断两个集合内容是否相同 23 6.3.13 Count 、LongCount集合的元素个数 23 6.3.14 Average 、Sum集合平均值求和 23 6.3.15 Max、Min 集合最大值,最小值 24 6.3.16 Aggregate 根据输入的表达式获取一个聚合值 24 6.3.17 DefaultIfEmpty 查询结果为空则返回默认值,浅复本 24 6.3.18 ToArray 将集合转换为数组,浅复本 24 6.3.19 ToList 将集合转换为List集合,浅复本 25 6.3.20 ToDictionary 将集合转换为集合,浅复本 25 7 Lambda表达式 25 7.1 例1(比效) 25 7.2 例2(多参) 27 7.3 例3(list.Where) 27 7.4 Lambda表达式Lifting 28 8 QuerySyntax 查询语法 29 8.1 from in select 30 8.2 orderby 排序 30 8.3 group by into 分组 31 8.4 join in on equals 联合查询 33 8.5 into 汇总 33 9 DataSource 数据绑定 34

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧