关于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。
虽然说是这么说,但是我对于这样区分的动机和概念还是有点模糊,那么他们在相对底层的实现上具体有什么差别呢?我们又该怎样很好的区分这两个类来做扩展之类的编码?
...全文
4559 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)
内容概要:本文围绕【复现IEEE二区文献】基于状态空间表示与组件连接法的构网型逆变器统一小信号建模框架研究,提出了一种适用于多控制策略构网型逆变器的小信号建模方法。该方法结合状态空间建模理论与组件连接法(Component Connection Method),实现了对复杂逆变器系统动态特性的精确描述,尤其适用于分析系统在不同运行工况下的稳定性。通过Matlab代码实现,构建了包含控制环路、滤波器、锁相环等关键模块的完整小信号模型,并利用特征值分析与模态参与度评估系统稳定性,解决了传统建模方法在面对多时间尺度、强耦合非线性控制结构时建模困难、精度不足的问题。研究还探讨了关键控制参数对系统稳定边界的影响,为构网型逆变器的参数整定与优化设计提供了理论依据和技术支撑。; 适合人群:具备电力电子、自动控制理论基础,从事新能源发电、微电网、电力系统稳定性研究的研究生、科研人员及工程技术人员,尤其适合致力于高水平期刊论文复现与仿真实践的科研工作者。; 使用场景及目标:① 掌握构网型逆变器统一小信号建模的核心方法,复现IEEE二区高水平文献成果;② 理解状态空间法与组件连接法在复杂电力电子系统建模中的集成应用;③ 利用Matlab进行特征值分析与稳定性判据研究,支撑科研仿真与论文写作;④ 为多逆变器并联系统、微电网稳定性分析等课题提供建模工具与技术路线参考。; 阅读建议:建议读者结合Matlab代码与文中建模流程逐步调试,重点关注各子模块状态方程的推导与系统整体矩阵组装过程,深入理解控制参数对系统极点分布的影响规律,建议配合其他稳定性分析案例进行对比学习以加深理解。
内容概要:WiFiSupply斯普莱WFS7000XB52AX5G是一款高性能、工业级的5G全网通+双频WIFI6无线AP基站,支持5G与工业大功率Wi-Fi链路无缝切换与带宽聚合,具备高达2974Mbps的双频带宽和1000Mbps以上的实际吞吐量。设备采用MIMO 4T4R架构,支持OFDMA、AI智能FastRoaming等先进技术,实现低至20ms的漫游切换延迟和超远传输距离(点对点桥接可达150公里以上)。产品具备IP68防水、-45~85℃宽温运行、多重看门狗、防浪涌、防静电等工业级防护设计,适用于复杂恶劣环境。支持胖瘦AP模式、多种认证与管理方式(含云平台、API接口),并集成丰富的网络安全与QoS功能,适用于智慧物流、工业4.0、巡检机器人、无人机、车载船舶等多种场景。; 适合人群:从事工业物联网、智能制造、自动化物流、智能交通等领域的网络工程师、系统集成商、设备制造商及技术决策人员。; 使用场景及目标:①实现移动设备(如AGV/AMR/巡检机器人)在高速移动中的零丢包、低延迟无线漫游;②在无固定网络覆盖区域构建高带宽、高可靠的远距离无线通信链路;③为5G与工业Wi-Fi双链路备份与聚合提供一体化解决方案,保障关键业务连续性;④在复杂电磁环境下实现稳定、安全的数据传输与远程控制。; 阅读建议:本产品技术参数详尽,建议结合具体应用场景重点关注其无线性能、漫游技术、供电方式与安装选项,并参考官方提供的管理平台与API接口文档进行系统集成与远程运维规划。

111,128

社区成员

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

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

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