程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> IEnumerable和IQueryable的區別以及背後的ExpressionTree表達式樹,cronexpression表達式

IEnumerable和IQueryable的區別以及背後的ExpressionTree表達式樹,cronexpression表達式

編輯:C#入門知識

IEnumerable和IQueryable的區別以及背後的ExpressionTree表達式樹,cronexpression表達式


關於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呈現給我們的是表達式而不是集合,通過這個表達式可以按需加載滿足條件的數據。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved