关于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. UART中的硬件流控RTS与CTS【转】

    转自:http://blog.csdn.net/zeroboundary/article/details/8966586 5/23/2013 5:13:04 PM at rock-chips insh ...

  2. H5开发APP考题和答案

    { "last_updated": { "$date": 1544276670569 }, "page_count": 1, "a ...

  3. 设置adb server的端口号

    在操作系统的系统环境里面,加一个环境变量: ANDROID_ADB_SERVER_PORT,值为9999,看自己喜欢.

  4. Java基础88 数据库设计的三大范式

    数据库的设计原则:建议设计的表尽量遵守三大范式 1.第一范式 要求表的每个字段必须是不可分割的独立单元 Student表:    name       -- 违反了第一范式             张 ...

  5. 为什么因式分解n=pq分别得到pq是求解密钥中d的关键

    从d的来源来说,它是这样来的: "找到一个数d,使得ed-1能够被z整除.即给定e,选择数d,使得ed被z除的余数为1",即  ed=1 (mod z) 上面这句话中,为了求d,我 ...

  6. vue报错 ModuleBuildError: Module build failed: Error: `sass-loader` requires `node-sass` >=4. Please install a compatible version.

    解决方法: 输入命令:cnpm install node-sass@latest

  7. HNOI2019滚粗记

    HNOI2019滚粗记 标签: 游记 Day -1 在学校打摆被抓. Day 0 在家打摆. Day 1 来长沙理工大学打摆 开场看完题之后,感觉T3不太可做,然后T1T2又显得特别套路,然后把T2 ...

  8. MySQL的lock tables和unlock tables的用法(转载)

    早就听说lock tables和unlock tables这两个命令,从字面也大体知道,前者的作用是锁定表,后者的作用是解除锁定.但是具体如何用,怎么用,不太清楚.今天详细研究了下,总算搞明白了2者的 ...

  9. 002.DHCP配置

    一 DHCP服务器安装包 yum -y install dhcp 二 对应端口 ipv4 udp67.udp68 ipv6 udp546.udp547 三 文件路径 服务名:dhcpd 主配置文件:/ ...

  10. linux下mysql操作命令集合

    转载:http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/10/18/2216279.html 1.linux下启动mysql的命令:mysq ...