关于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。
虽然说是这么说,但是我对于这样区分的动机和概念还是有点模糊,那么他们在相对底层的实现上具体有什么差别呢?我们又该怎样很好的区分这两个类来做扩展之类的编码?
...全文
4385 35 打赏 收藏 转发到动态 举报
AI 作业
写回复
用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)

111,098

社区成员

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

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

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