久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

深入解析LINQ框架

 黃爸爸好 2021-11-28

LINQ的查詢表達(dá)式其實是C#之上的語法糖,。

1】.擴(kuò)展Linq to Object (應(yīng)用框架具有查詢功能)

我們知道LINQ所支持的查詢范圍主要在IEnumerable、IQueryable這兩個方面,,對于我們想要擴(kuò)展LINQ的查詢能力也主要集中在這兩塊,。很多時候我們在編寫應(yīng)用框架的時候,都會自己去實現(xiàn)IEnumerble對象,,一般不會用系統(tǒng)提供的集合類,,這樣為了框架的OO性,,上下文連貫性,,更模型化。如果應(yīng)用框架具備一定的查詢能力是不是很方便些,。比如你在開發(fā)一個關(guān)于數(shù)據(jù)密集性的框架,,可能不是實時的持久化,但是能在外部提供某種查詢工具來查詢內(nèi)存中的數(shù)據(jù),,所以這個時候需要我們能擴(kuò)展LINQ的Object查詢能力,。這一節(jié)我們就來學(xué)習(xí)怎么擴(kuò)展Linq to Object。

LINQ查詢Object是基于IEnumerable對象的,,不是集合對象有什么好查的,。對于IEnumerable對象的LINQ查詢是Enumerable靜態(tài)對象在支撐著,然后通過匿名表達(dá)式來表示邏輯,,這樣就能順其自然的查詢集合,。那么我們該如何下手?jǐn)U展Linq to Object?其實也就是兩點可以擴(kuò)展,,要么提供擴(kuò)展方法來擴(kuò)展IEnumerable對象,,當(dāng)然你別企圖想讓VS支持某種關(guān)鍵字讓你對應(yīng)擴(kuò)展方法。還有就是繼承IEnumerable對象讓我們自己的集合類型具備LINQ的強(qiáng)類型的查詢能力,。當(dāng)然具體要看我們需求,,從技術(shù)角度看目前只有這兩點可以擴(kuò)展。

如果我們使用擴(kuò)展方法那么只能是擴(kuò)展IEnumerable對象,,這沒有問題,。我們可以很方便的在LINQ的表達(dá)式中調(diào)用我們自己的擴(kuò)展方法,讓自己的方法跟著一起鏈?zhǔn)讲樵?。如果我們從繼承IEnumerable對象擴(kuò)展,,那么情況會有點小復(fù)雜,,你的擴(kuò)展方法中要擴(kuò)展的對象一定要具體的給出對象的定義才行,如果你擴(kuò)展的對象不能和繼承的對象保持一直,,那么你將斷掉所有的擴(kuò)展方法,。

1.1】.通過添加IEnumerable對象的擴(kuò)展方法

下面我們通過具體的例子來分析一下上面的理論,先看看通過擴(kuò)展方法來擴(kuò)展系統(tǒng)的IEnumerable對象,。

代碼段:Order類


 /// 訂單類型 
    public class Order
    {
        // 訂單名稱                     
        public string OrderName { get; set; }
        // 下單時間 
        public DateTime OrderTime { get; set; }
        //訂單編號 
        public Guid OrderCode { get; set; }
    }
復(fù)制代碼

這是個訂單類純粹是為了演示而用,,里面有三個屬性分別是'OrderName(訂單名稱)'、'OrderTime(下單時間)',、'OrderCode(訂單編號)',,后面我們將通過這三個屬性來配合示例的完成。

如果我們是直接使用系統(tǒng)提供的IEnumerable對象的話,,只需要構(gòu)建IEnumerable對象的擴(kuò)展方法就能實現(xiàn)對集合類型的擴(kuò)展,。我假設(shè)使用List來保存一批訂單的信息,但是根據(jù)業(yè)務(wù)邏輯需要我們要通過提供一套獨立的擴(kuò)展方法來支持對訂單集合數(shù)據(jù)的處理,。這一套獨立的擴(kuò)展方法會跟隨著當(dāng)前系統(tǒng)部署,,不作為公共的開發(fā)框架的一部分。這樣很方便也很靈活,,完全可以替代分層架構(gòu)中的部分Service層,、BLL層的邏輯代碼段,看上去更為優(yōu)雅,。

再發(fā)散一下思維,,我們甚至可以在擴(kuò)展方法中做很多文章,把擴(kuò)展方法納入系統(tǒng)架構(gòu)分析中去,,采用擴(kuò)展方法封裝流線型的處理邏輯,,對業(yè)務(wù)的碎片化處理、驗證的鏈?zhǔn)教幚矶际呛懿诲e的,。只有這樣才能真正的讓這種技術(shù)深入人心,,才能在實際的系統(tǒng)開發(fā)當(dāng)中去靈活的運用。

下面我們來構(gòu)建一個簡單的IEnumerable擴(kuò)展方法,,用來處理當(dāng)前集合中的數(shù)據(jù)是否可以進(jìn)行數(shù)據(jù)的插入操作,。

代碼段:OrderCollectionExtent靜態(tài)類

public static class OrderCollectionExtent
{
    public static bool WhereOrderListAdd<T>(this IEnumerable<T> IEnumerable) where T : Order
    {
        foreach (var item in IEnumerable)
        {
            if (item.OrderCode != null && !String.IsNullOrEmpty(item.OrderName) && item.OrderTime != null)
            {
                continue;
            }
            return false;
        }


        return true;
    }
}

OrderCollectionExtent是個簡單的擴(kuò)展方法類,該類只有一個WhereOrderListAdd方法,,該方法是判斷當(dāng)前集合中的Order對象是否都滿足了插入條件,,條件判斷不是重點,僅僅滿足例子的需要,。這個方法需要加上Order類型泛型約束才行,,這樣該擴(kuò)展方法才不會被其他的類型所使用。

   List<Order> orderlist = new List<Order>() {
            new Order(){ OrderCode=Guid.NewGuid(), OrderName='水果', OrderTime=DateTime.Now},
            new Order(){ OrderCode=Guid.NewGuid(), OrderName='辦公用品',OrderTime=DateTime.Now} 
        }; 

        if (orderlist.WhereOrderListAdd()) 
        { 
            //執(zhí)行插入 
        }

如果.NET支持?jǐn)U展屬性【不過微軟后期肯定是會支持屬性擴(kuò)展的】,,就不會使用方法來做類似的判斷了,。這樣我們是不是很優(yōu)雅的執(zhí)行了以前BLL層處理的邏輯判斷了,,而且這部分的擴(kuò)展方法是可以動態(tài)的更改的,完全可以建立在一個獨立的程序集當(dāng)中,。順便在擴(kuò)展點使用思路,,在目前MVVM模式中其實也可以將V中的很多界面邏輯封裝在擴(kuò)展方法中來減少VM中的耦合度和復(fù)雜度。包括現(xiàn)在的MVC都可以適當(dāng)?shù)牟捎脭U(kuò)展方法來達(dá)到更為便利的使用模式,。

但是大部分情況下我們都是針對所有的IEnunerale類型進(jìn)行擴(kuò)展的,,這樣可以很好的結(jié)合Linq的鏈?zhǔn)骄幊獭T砭瓦@么多,,根據(jù)具體項目需要適當(dāng)?shù)牟杉{,。

1.2】.通過繼承IEnumerable接口

我想大部分的情況下我們都是直接使用IEnumerable的實現(xiàn)類,但是在編寫系統(tǒng)組件,、框架的時候一般都是要自己去實現(xiàn)自己的迭代器類的,。那么這個時候的擴(kuò)展方法還能作用于我們繼承下來的類,這是相當(dāng)方便的,,不知不覺我們自己擴(kuò)展的組件將也會支持Linq的查詢,。但是這個時候應(yīng)該適當(dāng)?shù)目刂颇汜槍^承下來的類的擴(kuò)展,擴(kuò)展方法應(yīng)該是面向你內(nèi)部使用的,,不能污染到外部的對象,。

我們繼續(xù)看例子,,該例子是針對繼承IEnumerable來分析使用方式,;

public class OrderCollection : IEnumerable
{
    List<Order> orderList;
    public OrderCollection()
    {
        orderList = new List<Order>() {
            new Order() { OrderCode = Guid.NewGuid(), OrderName = '訂單1', OrderTime = DateTime.Now },
            new Order() { OrderCode = Guid.NewGuid(), OrderName = '訂單2', OrderTime = DateTime.Now }, 
            new Order() { OrderCode = Guid.NewGuid(), OrderName = '訂單3', OrderTime = DateTime.Now } 
        };
    }


    public IEnumerator<Order> GetEnumerator()
    {
        foreach (var order in orderList) { yield return order; }
    }


    IEnumerator IEnumerable.GetEnumerator()
    {
        foreach (var order in orderList) { yield return order; }
    }
}

這是個Order集合類型OrderCollection類,該類專門用來存放或處理Order類的,。不管是從兼容.NET2.0或者其他方面考慮都可能將集合的類型封裝在.NET2.0版本的程序集中,,在.NET2.0之上的版本都會提供擴(kuò)展版本的程序集,這個時候我們的擴(kuò)展方法要專門針對OrderCollection去編寫,,否則就會造成 IEnumerable對象的污染,。

public static OrderCollection GetOutOrderCollection(this OrderCollection OrderColl) { return OrderColl; }

這個時候會很干凈的使用著自己的擴(kuò)展方法,不會造成大面積的污染,。當(dāng)然一般都是依賴倒置原則都會有高層抽象,,不會直接擴(kuò)展實現(xiàn)類,這里只是簡單的介紹,。

1.3】.詳細(xì)的對象結(jié)構(gòu)圖

這個小結(jié)主要將IEnumerable及它的擴(kuò)展方法包括Linq的查詢進(jìn)行一個完整的結(jié)構(gòu)分析,,將給出詳細(xì)的對象結(jié)構(gòu)導(dǎo)圖。

對象靜態(tài)模型,、運行時導(dǎo)圖:

上圖中的關(guān)鍵部分就是i==10將被封裝成表達(dá)式直接送入Where方法,,而select后面的i也是表達(dá)式【(int i)=>i】,也將被送入Select方法,,這里就不畫出來了,。順著數(shù)字序號理解,,IEnumerable是Linq to Object的數(shù)據(jù)源,而Enumerable靜態(tài)類是專門用來擴(kuò)展Linq查詢表達(dá)式中的查詢方法的,,所以當(dāng)我們編寫Linq查詢IEnumerable集合是,,其實是在間接的調(diào)用這些擴(kuò)展方法,只不過我們不需要那么繁瑣的去編寫Lambda表達(dá)式,,由編輯器幫我們動態(tài)生成,。

小結(jié):本節(jié)主要講解了Linq to Object的原理,其實主要的原理就是Lambda表達(dá)式傳入到Enumerable擴(kuò)展方法當(dāng)中,,然后形成鏈?zhǔn)讲僮?。Linq 只是輔助我們快速查詢的語言,并不是.NET或者C#的一部分,,在任何.NET平臺上的語言中都可以使用,。下面我們將重點分析Linq to Provider,這樣我們才能真正的對LINQ進(jìn)行高級應(yīng)用,。

2.】.實現(xiàn)IQueryable ,、IQueryProvider接口

這篇文章的重點就是講解IQueryable、IQueryProvider兩個接口的,,當(dāng)我們搞懂了這兩個接口之后,,我們就可以發(fā)揮想象力的去實現(xiàn)任何一個數(shù)據(jù)源的查詢。IQueryable,、IQueryProvider兩接口還是有很多值得我們研究的好東西,,里面充斥大量的設(shè)計模式、數(shù)據(jù)結(jié)構(gòu)的知識,,下面我們就來慢慢的分析它的美,。

IQueryable接口是Linq to Provider的入口,非常有意思的是它并不是一個IQueryable來支撐一次查詢,。我們在編寫Linq語句的時候一般都是 where什么然后select 什么,,至少連續(xù)兩個擴(kuò)展方法的映射調(diào)用,但是朋友你知道它內(nèi)部是如何處理的嗎,?每當(dāng)Where過后緊接著Select他們是如何關(guān)聯(lián)一個完整的查詢的,?IQueryable并非IEnumerable對象,無法實時的做出處理然后將結(jié)果返回給下一個方法接著執(zhí)行,。那么它如何將片段性的執(zhí)行方法串成一個整的,、完整的查詢?下面我們將逐個的分析這其中要涉及到的模式,、數(shù)據(jù)結(jié)構(gòu),、框架原則,這些搞懂了之后代碼都是模型的表現(xiàn),也就順其自然的明白了,。

2.1】.延遲加載IEnumertor對象(提高系統(tǒng)性能)

延遲加載的技術(shù)其實在Linq之前就已經(jīng)在使用,,只不過很少有人去關(guān)注它,都被隱藏在系統(tǒng)框架的底層,。很多場合下我們需要自己去構(gòu)建延遲加載特性的功能,,在IEnumerable對象中構(gòu)建延遲基本上是通過yield return 去構(gòu)建一個狀態(tài)機(jī),當(dāng)進(jìn)行迭代的時候才進(jìn)行數(shù)據(jù)的返回操作,。那么在IQueryable中是通過執(zhí)行Provider程序來獲取數(shù)據(jù),,減少在一開始就獲取數(shù)據(jù)的性能代價。IQueryable繼承自IEnumerable接口,,也就是可以被foreach語法調(diào)用的,,但是在GetEnumerator方法中才會去執(zhí)行提供程序的代碼。我們來分析一下IQueryable接口的代碼,。

public IEnumerator GetEnumerator(){ return (Provider.Execute(Expression) as IEnumerable ).GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return (Provider.Execute(Expression) as IEnumerable).GetEnumerator(); }

這是IQueryable接口中從IEnumerable繼承下來的兩個返回IEnumerator接口類型的方法,,在我們目前使用的Linq to Sql、Linq to Entity中都會返回強(qiáng)類型的集合對象,,一般都不會實時的進(jìn)行數(shù)據(jù)查詢操作,,如果要想實時執(zhí)行需要進(jìn)行IQueryable.Provider.Execute方法的直接調(diào)用。

我們用圖來分析一下Linq to Provider中的延遲加載的原理,;

這段代碼不會被立即執(zhí)行,,我們跟蹤一下各個組成部分之間的執(zhí)行過程;

這幅圖重點是IQueryable對象的連續(xù)操作,,大致原理是每次執(zhí)行擴(kuò)展方法的時候都會構(gòu)造一個新的IQueryable,,本次的IQueryable對象將包含上次執(zhí)行的表達(dá)式樹,以此類推就形成了一顆龐大的表達(dá)式樹,。詳細(xì)的原理在下面幾小節(jié)中具體分析,。

最后Orderlist將是一個IQueryable類型的對象,,該對象中包含了完整的表達(dá)式樹,,這個時候如果我們不進(jìn)行任何的使用將不會觸發(fā)數(shù)據(jù)的查詢。這就是延遲加載的關(guān)鍵所在,。如果想立即獲取orderlist中的數(shù)據(jù)可以手動執(zhí)行orderlist.Provider.Execute(orderlist.Expression)來獲取數(shù)據(jù),。

2.2】.擴(kuò)展方法的擴(kuò)展對象之奧秘(this IQueryable source)

其實這里有一個思維陷阱,當(dāng)我們分析源碼的時候只將焦點集中在擴(kuò)展方法中的后面參數(shù)上,,而沒有集中精力考慮擴(kuò)展方法所擴(kuò)展的對象本身,,看似不同的方法位于不同的地方,其實他們來自一個地方,,所在的邏輯對象是一個,,但是這恰恰會造成我們分析問題的瓶頸,這里我們重點的講解一下擴(kuò)展方法所擴(kuò)展對象。我們直接用源碼進(jìn)行講解吧,;

public static IQueryable Select(this IQueryable source, Expression<func> selector) { 
if (source == null) { 
	throw Error.ArgumentNull('source'); 
} 
if (selector == null) { 
	throw Error.ArgumentNull('selector'); 
} 
return source.Provider.CreateQuery(Expression.Call(null, 
 ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(new Type[] { typeof(TSource), typeof(TResult) }), 
 new Expression[] { source.Expression, Expression.Quote(selector) })); 
}

這是Queryable類中的Select擴(kuò)展方法的源代碼,,它擴(kuò)展IQueryable對象,在方法內(nèi)部都是在使用source對象來操作,,source是擴(kuò)展對象的直接引用,。這是問題的重點,對擴(kuò)展方法,、鏈?zhǔn)骄幊滩皇煜さ呐笥押茈y將source能串聯(lián)到之前方法所返回的IQueryable對象上,。根據(jù)這里的代碼分析,source每次都代表著IQueryable實例,,不管你是哪次進(jìn)行方法的調(diào)用,,它都代表著你當(dāng)前調(diào)用方法的對象,所以不管我們進(jìn)行多少次的調(diào)用它們都是連貫的,,就好比數(shù)據(jù)結(jié)構(gòu)里面的雙向鏈表一樣,,這個方法處理完后,接著下一個方法都將是本對象的方法,。所以要注意本次的調(diào)用將是接著上一次調(diào)用,,而不是以個新的開始。理解這一點對后面的LINQ分析很關(guān)鍵,。

3.3】.分段執(zhí)行IQueryable中的子方法(Queryable中的擴(kuò)展方法)

都知道Linq的查詢是將一些關(guān)鍵字拼接起來的,,行成連續(xù)的查詢語義,這其中背后的原理文章上上下下也說過很多遍,,我想也應(yīng)該大致的了解了,。其實這有點像是把大問題分解成多個小問題來解決,但是又不全是為了分解問題而這樣設(shè)計,,在鏈?zhǔn)讲樵冎泻芏嚓P(guān)鍵字在不同的查詢上下文中都是公用的,,比如where可以用在查詢,也可以用在更新,、刪除,。這里討論的問題可能已經(jīng)超過LINQ,但是很有意義,,因為他們有著相似的設(shè)計模型,。

根據(jù)3.2圖中的意思,我們都已經(jīng)知道擴(kuò)展方法之間傳輸?shù)膶ο蠖际莵碜圆煌膶嵗莵碜砸粋€對象類型,,那么為什么要分段執(zhí)行每個關(guān)鍵字的操作呢,?我們還是用圖來幫助我們分析問題吧。

兩行代碼都引用了Where方法,,都需要拼接條件,,但是 Where方法所產(chǎn)生的條件不會影響你之前的方法。分段執(zhí)行的好處就在這里,最大粒度的脫耦才能最大程度的重用,。

3.4】.鏈?zhǔn)讲樵兎椒ǖ脑O(shè)計誤區(qū)(重點:一次執(zhí)行程序多次處理)

在使用IQueryable時,,我們嘗試分析源碼,看看IQueryable內(nèi)部使用原理來幫我們生成表達(dá)式樹數(shù)據(jù)的,,我們順其自然的看到了Provider屬性,,該屬性是IQueryProvider接口,根據(jù)注釋說明我們搞懂了它是最后執(zhí)行查詢的提供程序,,我們理所當(dāng)然的把IQueryable的開始實例當(dāng)成了查詢的入口,,并且在連續(xù)調(diào)用的擴(kuò)展方法當(dāng)中它都保持唯一的一個實例,最后它完整的獲取到了所有表達(dá)式,,形成一顆表達(dá)式樹,。但是IQueryable卻跟我們開了一個玩笑,它的調(diào)用到最后的返回不知道執(zhí)行多少了CreateQuery了,??此埔淮螆?zhí)行卻隱藏著多次方法調(diào)用,后臺暗暗的構(gòu)建了我們都不知道的執(zhí)行模型,,讓人欣喜若狂,。我們來揭開IQueryable在鏈?zhǔn)椒椒ㄖ械降资侨绾翁幚淼模纯此降撞氐挠卸嗌睢?/span>

public static IQueryable Where(this IQueryable source, Expression<func<tsource, bool>> predicate) {
 if (source == null) { throw Error.ArgumentNull('source'); }
 if (predicate == null) { throw Error.ArgumentNull('predicate'); } 
 return source.Provider.CreateQuery(Expression.Call(null, 
            ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(new Type[] { typeof(TSource) }), 
             new Expression[] { source.Expression, Expression.Quote(predicate) })); }

類似這段代碼的在文章的上面曾出現(xiàn)過,,大同小異,,我們下面詳細(xì)的分析一下它的內(nèi)部原理,到底是如何構(gòu)建一個動態(tài)卻是靜態(tài)的對象模型,。

這個方法有一個參數(shù),,是條件表達(dá)式,并且這個方法擴(kuò)展IQueryable接口,,任何派生著都能直接使用,。方法的返回類型也是IQueryable類型,返回類型和擴(kuò)展類型相同就已經(jīng)構(gòu)成鏈?zhǔn)骄幊痰淖钚…h(huán)路,。方法中有兩個判斷,,第一個是判斷是否是通過擴(kuò)展方法方式調(diào)用代碼的,防止我們直接使用擴(kuò)展方法,,第二個判斷是確定我們是否提供了表達(dá)式,。

那么重點是最后一行代碼,它包裹著幾層方法調(diào)用,,到底是啥意思呢?我們詳細(xì)分解后自然也就恍然大悟了,。

由于問題比較復(fù)雜,,這里不做全面的IQueryable的上下文分析,只保證本節(jié)的完整性。通過上圖中,,我們大概能分析出IQueryable對象是每次方法的調(diào)用都會產(chǎn)生一個新的實例,,這個實例接著被下一個方法自然的接受,依次調(diào)用,。

面向接口的設(shè)計追求職責(zé)分離,,這里為什么把執(zhí)行和創(chuàng)建IQueryable都放到IQueryProvider中去?如果把創(chuàng)建IQueryable提取處理形成獨立的創(chuàng)建接口我覺得更巧妙,,當(dāng)然這只是我的猜測,,也許是理解錯了。

4】.LINQ查詢表達(dá)式和鏈?zhǔn)讲樵兎椒ㄆ鋵嵍际强諝ぷ?/h2>

LINQ的真正意圖是在方便我們構(gòu)建表達(dá)式樹(ExpressionTree),,手動構(gòu)建過表達(dá)式樹的朋友都會覺得很麻煩(對動態(tài)表達(dá)式有興趣的可以參見本人的“.NET深入解析LINQ框架(三:LINQ優(yōu)雅的前奏)”一文),,所以我們可以通過直接編寫Lambda的方式調(diào)用擴(kuò)展方法,由于LambdaExpression也是來自于Expression,,而Expression又是來自LambdaExpression,,別被這些搞暈,Expression其實是簡化我們使用表達(dá)式的方式,。對于Expression的編譯方式是編輯器幫我們生成好的,,在運行時我們只管獲取ExpressionTree就行了。LINQ的查詢表達(dá)式是通過擴(kuò)展方法橫向支撐的,,你不用LINQ也一樣可以直接使用各個擴(kuò)展方法,,但是那樣會很麻煩,開發(fā)速度會很慢,,最大的問題不在于此,,而是沒有統(tǒng)一的查詢方式來查詢所有的數(shù)據(jù)源。LINQ的本意和初衷是提供統(tǒng)一的方式來供我們查詢所有的數(shù)據(jù)源,,這點很重要,。

5】詳細(xì)的對象結(jié)構(gòu)圖(對象的執(zhí)行原理)

這篇文章的重點就在這一節(jié)了,上面說了那么多的話如果朋友能懂還好不懂的話還真是頭疼,。這一節(jié)我將給出LINQ的核心的執(zhí)行圖,,我們將很清楚的看見LINQ的最終表達(dá)式樹的對象結(jié)構(gòu),它是如何構(gòu)建一棵完整的樹形結(jié)構(gòu)的,,IQueryable接口是怎么和IQueryProvider接口配合的,,為什么IQueryable具備延遲加載的能力。文章的最后將給出一個完整的Linq to Provider的小例子,,喜歡擴(kuò)展LINQ的朋友肯定會喜歡的,。

上圖看上去可能會很亂,但是靜下心來看還是能理解的,,按照DbQueryable生命周期來看,,之上而下,,如果有問題可以回復(fù)評論進(jìn)一步探討。

6】.IQueryable與IQueryProvider一對一的關(guān)系能否改成一對多的關(guān)系

IQueryable對象都有一個配套的IQueryProvider對象,,在頻繁的創(chuàng)建IQueryable的時候都會重新創(chuàng)建IQueryProvider對象,,畢竟是一種浪費。我們可以適當(dāng)?shù)男薷膶崿F(xiàn)IQueryable類的內(nèi)部結(jié)構(gòu),,讓每次創(chuàng)建IQueryable之后能重用上一次的IQueryProvider的對象,,畢竟IQueryProvider對象沒有任何的中間狀態(tài)的數(shù)據(jù),只是CreateQuery,、 Execute兩個方法,。這里只是本人的一點小小的改進(jìn)想法,不一定需要考慮這些,。

7】.完整的自定義查詢

LINQ的分析接近尾聲了,,這篇文章將是深入分析LINQ的最后一篇。既然已經(jīng)結(jié)束了LINQ的全部分析,,那么我們動手寫一個小例子,,作為想擴(kuò)展LINQ的小雛形。該例子不會涉及到對表達(dá)式樹的分析,,畢竟表達(dá)式樹的分析并非易事,,后面會有專本的文章來剖析表達(dá)式樹的完整結(jié)構(gòu),這里只是全盤的IQueryable和IQueryProvider的實現(xiàn),。

ORM一直是我們比較喜歡去寫的框架,,這里就使用自定義的IQueryable來查詢相應(yīng)的對象實體。首先我們需要繼承IQueryable接口來讓LINQ能查詢我們自己的數(shù)據(jù)上下文,。

public class DbQuery : IQueryable, IDisposable
{
    public DbQuery()
    {
        Provider = new DbQueryProvider();
        Expression = Expression.Constant(this);
        //最后一個表達(dá)式將是第一IQueryable對象的引用,。  
    }
    public DbQuery(Expression expression) { Provider = new DbQueryProvider(); Expression = expression; }
    public Type ElementType
    {
        get { return typeof(T); }
        private set { ElementType = value; }
    }
    public System.Linq.Expressions.Expression Expression { get; private set; }
    public IQueryProvider Provider { get; private set; }
    public IEnumerator GetEnumerator() { return (Provider.Execute(Expression) as IEnumerable).GetEnumerator(); }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return (Provider.Execute(Expression) as IEnumerable).GetEnumerator();
    }
    public void Dispose() { }
}

下面需要實現(xiàn)提供程序:

public class DbQueryProvider : IQueryProvider
{
    public IQueryable CreateQuery(System.Linq.Expressions.Expression expression)
    {
        return new DbQuery();
    }


    public IQueryable CreateQuery(System.Linq.Expressions.Expression expression)
    {
        //這里牽扯到對表達(dá)式樹的分析,就不多說了,。 
        throw new NotImplementedException();
    }


    public TResult Execute(System.Linq.Expressions.Expression expression)
    {
        return default(TResult);
        //強(qiáng)類型數(shù)據(jù)集 
    }
    public object Execute(System.Linq.Expressions.Expression expression)
    {
        return new List<object>();
        //弱類型數(shù)據(jù)集  
    }
}

我們看看如何使用,;

 using (DbQuery dbquery = new DbQuery()) {
            var OrderList = from order in dbquery 
                            where order.OrderName == '111' 
                            select order; 
            OrderList.Provider.Execute>(OrderList.Expression);
            //立即執(zhí)行  
            foreach (var o in OrderList) 
            { 
            //延遲執(zhí)行  
            } 
        }

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多