天天看點

打造自己的LINQ Provider(中):IQueryable和IQueryProvider

在.NET Framework 3.5中提供了LINQ 支援後,LINQ就以其強大而優雅的程式設計方式赢得了開發人員的喜愛,而各種LINQ Provider更是滿天飛,如LINQ to NHibernate、LINQ to Google等,大有“一切皆LINQ”的趨勢。LINQ本身也提供了很好的擴充性,使得我們可以輕松的編寫屬于自己的LINQ Provider。 

本文為打造自己的LINQ Provider系列文章第二篇,主要詳細介紹自定義LINQ Provider中兩個最重要的接口IQueryable和IQueryProvider。

<a href="http://11011.net/software/vspaste"></a>

這裡将傳回兩條結果,如下圖所示:

這裡就有一個問題,為什麼在LINQ to Objects中傳回的是IEnumerable&lt;T&gt;類型的資料而不是IQueryable&lt;T&gt;呢?答案就在本文的開始,在LINQ to Objects中查詢表達式或者Lambda表達式并不翻譯為表達式目錄樹,因為LINQ to Objects查詢的都是實作了IEnmerable&lt;T&gt;接口的資料,是以查詢表達式或者Lambda表達式都可以直接轉換為.NET代碼來執行,無需再經過轉換為表達式目錄這一步,這也是LINQ to Objects比較特殊的地方,它不需要特定的LINQ Provider。我們可以看一下IEnumerable&lt;T&gt;接口的實作,它裡面并沒有Expression和Provider這樣的屬性,如下圖所示:

至于LINQ to Objects中所有的标準查詢操作符都是通過擴充方法來實作的,它們在抽象類Enumerable中定義,如其中的Where擴充方法如下代碼所示:

運作這段代碼,雖然它的輸出結果與上面的示例完全相同,但它們查詢的機制卻完全不同:

在.NET中,IQueryable&lt;T&gt;繼承于IEnumerable&lt;T&gt;和IQueryable接口,如下圖所示:

這裡有兩個很重要的屬性Expression和Provider,分别表示擷取與IQueryable 的執行個體關聯的表達式目錄樹和擷取與此資料源關聯的查詢提供程式,我們所有定義在查詢表達式中方法調用或者Lambda表達式都将由該Expression屬性表示,而最終會由Provider表示的提供程式翻譯為它所對應的資料源的查詢語言,這個資料源可能是資料庫,XML檔案或者是WebService等。該接口非常重要,在我們自定義LINQ Provider中必須要實作這個接口。同樣對于IQueryable的标準查詢操作都是由Queryable中的擴充方法來實作的,如下代碼所示:

最後還有一點,如果我們定義的查詢需要支援Orderby等操作,還必須實作IOrderedQueryable&lt;T&gt; 接口,它繼承自IQueryable&lt;T&gt;,如下圖所示:

在認識了IQueryable接口之後,我們再來看看在自定義LINQ Provider中另一個非常重要的接口IQueryProvider。它的定義如下圖所示:

看到這裡兩組方法的參數,其實大家已經可以知道,Provider負責執行表達式目錄樹并傳回結果。如果是LINQ to SQL的Provider,則它會負責把表達式目錄樹翻譯為T-SQL語句并并傳遞給資料庫伺服器,并傳回最後的執行的結果;如果是一個Web Service的Provider,則它會負責翻譯表達式目錄樹并調用Web Service,最終傳回結果。

這裡四個方法其實就兩個操作CreateQuery和Execute(分别有泛型和非泛型),CreateQuery方法用于構造一個 IQueryable&lt;T&gt; 對象,該對象可計算指定表達式目錄樹所表示的查詢,傳回的結果是一個可枚舉的類型,;而Execute執行指定表達式目錄樹所表示的查詢,傳回的結果是一個單一值。自定義一個最簡單的LINQ Provider,至少需要實作IQueryable&lt;T&gt;和IQueryProvider兩個接口,在下篇文章中,你将看到一個綜合的執行個體。

通過前面的講解,我們可以想到,對于LINQ的擴充有兩種方式,一是借助于LINQ to Objects,如果我們所做的查詢直接在.NET代碼中執行,就可以實作IEnumerable&lt;T&gt;接口,而無須再去實作IQueryable并編寫自定義的LINQ Provider,如.NET中内置的List&lt;T&gt;等。如我們可以編寫一段簡單自定義代碼:

第二種擴充LINQ的方式當然就是自定義LINQ Provider了,我們需要實作IQueryable&lt;T&gt;和IQueryProvider兩個接口,下面先給出一段簡單的示意代碼,在下一篇中我們将完整的來實作一個LINQ Provider。如下代碼所示:

上面這兩個接口都沒有完成,這裡隻是示意性的代碼,如果實作了這兩個接口,我們就可以像下面這樣使用了(當然這樣的使用是沒有意義的,這裡隻是為了示範):

本文介紹了在自定義LINQ Provider中兩個最重要的接口IQueryable和IQueryProvider,希望對大家有所幫助,下一篇我我們将開發一個完整的自定義LINQ Provider。

本文轉自lihuijun51CTO部落格,原文連結: http://blog.51cto.com/terrylee/94939,如需轉載請自行聯系原作者