关于IEnumerable和IQueryable的区别,这事还要从泛型委托Func<T>说起。来看一个简单的泛型委托例子:

    class Program
    {
        static void Main(string[] args)
        {
            Func<int, bool> f = i => i > 5;
            Console.WriteLine(f(3));
            Console.WriteLine(f(10));
            Console.ReadKey();
        }
    }

Func<T>是"语法糖",实际上,编译器在内部会生成一个临时方法,再执行该方法。等同于如下:

    class Program
    {
        static void Main(string[] args)
        {
            Func<int, bool> f = DoSth;
            Console.WriteLine(f(3));
            Console.ReadKey();
        }

        static bool DoSth(int i)
        {
            return i > 5;
        }
    }

以上,.NET内部运作的路径是:编写C#代码→编译器编译成中间语言IL→运行时JIT编译成本地语言执行

■ 使用表达式树 Expression Tree

可是,有时候我们希望在运行时执行代码,该怎么办呢?

.NET为我们提供了Expression Tree,允许我们在运行时执行代码。

比如以上Func<int, bool> f = i => i > 5;这个表达式,Expression Tree这样理解这个表达式:

○ f是Expression<Func<int, bool>>类型,级Expression<TDelegate>类型
○ =>被理解成BinaryExpression类型
○ =>左右两边的i被理解成ParameterExpression
○ =>右边的5被理解成ConstantExpression

于是,如果我们用Expression Tree,在运行时执行代码,可以按如下写:

    class Program
    {
        static void Main(string[] args)
        {
            //Func<int, bool> f = i => i > 5;
            ParameterExpression iParam = Expression.Parameter(typeof (int), "i");
            ConstantExpression constExp = Expression.Constant(5, typeof (int));
            BinaryExpression greaterThan = Expression.GreaterThan(iParam, constExp);
            Expression<Func<int, bool>> f = Expression.Lambda<Func<int, bool>>(greaterThan, iParam);

            Func<int, bool> myDele = f.Compile();
            Console.WriteLine(myDele(3));
            Console.WriteLine(myDele(10));
            Console.ReadKey();
        }
    }

■ IQueryable和IEnumerable的区别

现在,可以看一个IEnumerable的例子了:

   class Program
    {
        static void Main(string[] args)
        {

            int[] intArr = new[] {1, 2, 3, 6, 8};
            IEnumerable<int> result = Enumerable.Where(intArr, i => i > 5);

            foreach (var item in result)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        }
    }


来看一下Enumerable,实现了IEnumerable接口,它的定义:

再来看Queryable,实现了IQueryable接口,它的定义:

发现,Enumerable和Queryable很多方法同名,但参数接收的参数类型是不一样的,Enumerable接收的参数类型是委托Func<TDelegate>,Querable接收的参数类型是Expression<Func<TDelegate>>,其类型是Expression Tree,是表达式树。

所以,有关IEnumerable<T>的表达式是在编译期确定的,有关IQueryable<T>的表达式是在运行时确定的。

■ 在Entity Framework应用实例中体会IQueryable<T>

首先在控制台应用程序中应用Entity Framework组件。

创建有关Entity Framework的上下文类,类,初始数据:

    public class Person
    {
        [Key]
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }

    public class MyContext : DbContext
    {
        public MyContext() : base("myConn")
        {
            Database.SetInitializer(new DbInirializer());
        }
        public DbSet<Person> People { get; set; }
    }

    public class DbInirializer : CreateDatabaseIfNotExists<MyContext>
    {
        protected override void Seed(MyContext context)
        {
            IList<Person> people = new List<Person>();
            people.Add(new Person(){Name = "张三",Age = 21});
            people.Add(new Person() { Name = "李四", Age = 22 });
            people.Add(new Person() { Name = "赵五", Age = 23 });

            foreach (var item in people)
            {
                context.People.Add(item);
            }
            base.Seed(context);
        }
    }


以上,如果转到DbSet的定义,我们可以看到DbSet实现了IQueryable接口。

配置连接字符串。

<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
    <connectionStrings>
    <add name="myConn"
       connectionString="Data Source=.;User=yourusename;Password=yourpassword;Initial Catalog=MyTest;Integrated Security=True"
       providerName="System.Data.SqlClient"/>
  </connectionStrings>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>    

在主程序中:

    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new MyContext())
            {
                foreach (var item in context.People)
                {
                    Console.WriteLine(item.Name);
                }
            }
            Console.ReadKey();
        }
    }

现在来体会IQueryable<T>的一些特性。

我们知道,DbSet实现了IQuerayble接口,于是上下文的的People属性类型是IQueryable<Person>。

通过,

IQueryable<Person> people = context.People;

得到的people是表达式,是sql语句,现在尝试打印不同情况下的people表达式。

    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new MyContext())
            {
                IQueryable<Person> people = context.People;

                var r = new Random();
                Func<bool> rBool = () => r.Next()%2 == 0;

                Console.WriteLine(people);

                if (rBool())
                {
                    people = people.Where(p => p.Age > 21);
                    Console.WriteLine(people);
                }
                else
                {
                    people = people.OrderBy(p => p.Age);
                    Console.WriteLine(people);
                }

            }
            Console.ReadKey();
        }
    }

由此可以看出:IQueryable呈现给我们的是表达式而不是集合,通过这个表达式可以按需加载满足条件的数据。

IEnumerable和IQueryable的区别以及背后的ExpressionTree表达式树的更多相关文章

  1. IEnumerable 与 Iqueryable 的区别

    IEnumerable 和 IQueryable   共有两组 LINQ 标准查询运算符,一组在类型为 IEnumerable<T> 的对象上运行,另一组在类型为 IQueryable&l ...

  2. IEnumerable和IQueryable的区别

    转自:http://www.cnblogs.com/fly_dragon/archive/2011/02/21/1959933.html IEnumerable接口 公开枚举器,该枚举器支持在指定类型 ...

  3. IEnumerable和IQueryable在使用时的区别

    最近在调研数据库查询时因使用IEnumerable进行Linq to entity的操作,造成数据库访问缓慢.此文讲述的便是IEnumerable和IQueryable的区别. 微软对IEnumera ...

  4. Entity Framework返回IEnumerable还是IQueryable?

    在使用EF的过程中,我们常常使用repository模式,本文就在repository层的返回值是IEnumerable类型还是IQueryable进行探讨. 阅读目录: 一.什么是Repositor ...

  5. 再讲IQueryable<T>,揭开表达式树的神秘面纱

    接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...

  6. 【转】再讲IQueryable<T>,揭开表达式树的神秘面纱

    [转]再讲IQueryable<T>,揭开表达式树的神秘面纱 接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个 ...

  7. IEnumerable 和 IQueryable 区别

    IQueryable继承自IEnumerable,所以对于数据遍历来说,它们没有区别. 但是IQueryable的优势是它有表达式树,所有对于IQueryable的过滤,排序等操作,都会先缓存到表达式 ...

  8. IEnumerable,IQueryable的区别

    IEnumerable,IQueryable之前世今生 IEnumerable<T>在.Net2.0中我们已经很熟悉了.你想要利用Foreach迭代吗?实现IEnumerable<T ...

  9. IEnumerable<T>和IQueryable<T>区别

    LINQ查询方法一共提供了两种扩展方法,在System.Linq命名空间下,有两个静态类:Enumerable类,它针对继承了IEnumerable<T>接口的集合进行扩展:Queryab ...

随机推荐

  1. CentOS安装SVN客户端

    1.检查系统是否已经安装如果安装就卸载 rpm -qa subversion yum remove subversion 2.安装 yum install subversion 3.建立SVN库 mk ...

  2. Socket心跳包机制总结【转】

    转自:https://blog.csdn.net/qq_23167527/article/details/54290726 跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器, ...

  3. git学习——Git 基础要点【转】

    转自:http://blog.csdn.net/zeroboundary/article/details/10549555 简单地说,Git 究竟是怎样的一个系统呢?请注意,接下来的内容非常重要,若是 ...

  4. linux修改文件打开最大数(ulimit命令)

    解除 Linux 系统的最大进程数和最大文件打开数限制:vi /etc/security/limits.conf# 添加如下的行* soft noproc 65536 * hard noproc 65 ...

  5. 深入理解java虚拟机-00

    这本书买了有两年了,只有买回来翻了两页...今天电脑有点卡,游戏玩不了了,就来看看这本书. 首先看了序言,这本书是第二版,讲解的jdk版本是1.7,现在公司用的1.8,而且1.8的改动也挺大的,不过在 ...

  6. JavaScript:document.execCommand()的用法

    document.execCommand()的用法小记 一.语法 execCommand方法是执行一个对当前文档,当前选择或者给出范围的命令.处理Html数据时常用. 如下格式:document.ex ...

  7. UFLDL 教程学习笔记(一)

    ufdl的新教程,从基础学起.第一节讲的是线性回归.主要目的是熟悉目标函数,计算梯度和优化. 按着教程写完代码后,总是编译出错,一查是mex的原因,实在不想整了. 这位博主用的是向量,比较简洁:htt ...

  8. hdu 6118度度熊的交易计划(费用流)

    度度熊的交易计划 Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  9. IntelliJ IDEA快捷键:Shift+Esc

    Shift+Esc moves the focus to the editor and also hides the current (or last active) tool window. 将焦点 ...

  10. The last access date is not changed even after reading the file on Windows 7

    https://superuser.com/questions/251263/the-last-access-date-is-not-changed-even-after-reading-the-fi ...