<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      LINQ之路 7:子查詢、創建策略和數據轉換

      在前面的系列中,我們已經討論了LINQ簡單查詢的大部分特性,了解了LINQ的支持計術和語法形式。至此,我們應該可以創建出大部分相對簡單的LINQ查詢。在本篇中,除了對前面的知識做個簡單的總結,還會介紹幾種創建更復雜查詢的方式,讓我們在面對更復雜的場景時也能輕松面對,包括:子查詢、創建策略和數據轉換。

      子查詢

      在創建一個復雜的查詢時,通常我們需要用到子查詢。相信大家都記得SQL查詢里的子查詢,在創建LINQ查詢時也是如此。在LINQ中,對于方法語法,一個子查詢包含在另外一個查詢的lambda表達式中,對于查詢表達式語法來講,所有不是from子句中引用的查詢都是子查詢。

      下面的查詢使用子查詢來對last name進行排序,語句中的n.Split().Last()就是一個子查詢:

                  string[] names = { "David Tim", "Tony Sin", "Rager Witers" };
      IEnumerable<string> query = names.OrderBy(n => n.Split().Last());

      子查詢的作用域限定在當前的lambda表達式中,并且可以引用外部lambda表達式的參數(查詢表達式的范圍變量)。

      下面的查詢獲取所有長度最短的名字(注意:可能有多個):

              static void TestSubQuery()
      {
      string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
      // 獲取所有長度最短的名字(注意:可能有多個)
      IEnumerable<string> outQuery = names
      .Where(n => n.Length == names     // 感謝A_明~堅持的指正,這里應該為==

      .OrderBy(n2 => n2.Length)
      .Select(n2 => n2.Length).First()); // Tom, Jay"

      // 與上面方法語法等價的查詢表達式
      IEnumerable<string> outQuery2 =
      from n in names
      where n.Length ==            // 感謝A_明~堅持的指正,這里應該為==

      (from n2 in names orderby n2.Length select n2.Length).First()
      select n;

      // 我們可以使用Min查詢運算符來簡化
      IEnumerable<string> outQuery2 =
      from n in names
      where n.Length == names.Min(n2 => n2.Length)
      select n;
      }

      因為外部范圍變量在子查詢的作用域內,所以我們不能再次使用n作為內部查詢的范圍變量。

      一個子查詢在包含它的lambda表達式執行時被執行,這意味著子查詢的執行取決于外部查詢。需要注意的是:本地查詢(LINQ to Objects)和解釋查詢(LIQN to SQL)對于子查詢的處理方式是不一樣的。對于本地查詢,對于外部查詢的每一次循環,子查詢都會被重新執行一次。在稍后“解釋查詢”一篇中, 我們會看到,外部查詢和子查詢是作為一個單元進行處理的,這樣,只需一次到遠程數據源(如數據庫)的連接。所以上面的例子對于一個數據庫查詢來說非常適合,但對于一個內存中的集合來說卻效率低下,這時我們可以把子查詢分離出來對讓它只執行一次(這樣它不再是一個子查詢)。

                  int shortest = names.Min(n => n.Length);
      IEnumerable<string> query = from n in names
      where n.Length == shortest
      select n;

      在延遲執行一篇中,我們說到元素和集合運算符如First和Count會讓一個查詢立即執行。但對一個子查詢來說,即使是元素和集合運算符也不會改變外部查詢延遲執行的特性。這是因為,不管是對本地查詢還是通過表達式樹訪問的解釋查詢,子查詢是間接調用的。

       

      LINQ查詢創建策略

      通過前面幾篇的討論學習,我們已經了解了怎么去寫一個比較簡單的LINQ查詢,也知道了創建LINQ查詢的兩種方式:方法語法和查詢表達式。在這里,我們會描述三種創建復雜LINQ查詢的創建策略:

      漸進式創建查詢

      漸進式創建查詢就是通過鏈接查詢運算符的方式來創建LINQ查詢。因為每一個查詢運算符返回一個裝飾者sequence,所以我們可以在其之上繼續調用其它查詢運算符。使用這種方式有如下幾個優點:

      • 使得查詢易于編寫
      • 我們可以根據條件來決定是否調用某個查詢運算符,如:if (includeFilter) query = query.Where(…)

      漸進的方式通常是對查詢的創建有益的,考慮如下的例子:我們需要在名字列表中去除所有名字的元音字母,然后對長度大于2的名字進行排序。在方法語法中,我們可以在一個表達式中完成這個查詢:

                  string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
      IEnumerable<string> query = names
      .Select(n => n.Replace("a", "").Replace("e", "").Replace("i", "")
      .Replace("o", "").Replace("u", ""))
      .Where(n => n.Length > 2)
      .OrderBy(n => n); // Result: Dck, Hrry, Mry

      如果直接將上面的query改寫成查詢表達式語法,我們將會遇到麻煩,這時因為查詢表達式要求要以Select或Group結束。但在上面的查詢中,我們需要先做Select(結果投影)去除元音字母,再做過濾和排序。如果把Select直接放到后面,那么結果將會被改變。幸運的是,我們還是有辦法讓查詢表達式來完成上面的工作,得到我們期望的結果。 第一種方式就是查詢表達式的漸進式(分步)查詢:

                  IEnumerable<string> query =
      from n in names
      select n.Replace("a", "").Replace("e", "").Replace("i", "")
      .Replace("o", "").Replace("u", "");

      query = from n in query
      where n.Length > 2
      orderby n
      select n; // Result: Dck, Hrry, Mry

      into關鍵字

      在我們前面查詢表達式的例子中,select關鍵字的出現也就意味著查詢的結束了。而into關鍵字讓我們在結果投影之后還可以繼續我們的查詢,它是對分步構建查詢表達式的一種簡寫方式。現在我們可以使用into關鍵字來重寫上例中的查詢:

                  IEnumerable<string> query =
      from n in names
      select n.Replace("a", "").Replace("e", "").Replace("i", "")
      .Replace("o", "").Replace("u", "")
      into noVowel
      where noVowel.Length > 2
      orderby noVowel
      select noVowel; // Result: Dck, Hrry, Mry

      我們只能在select和group子句后面使用into關鍵字,它會重新開始一個查詢,讓我們可以繼續引入where, orderby和select子句。盡管表面上看,我們重新創建了一個新的查詢,但當上面的查詢被翻譯成方法語法時,它只是一個查詢,一個鏈接了多個運算符的查詢,所以上面的寫法不會造成性能問題。

      需要注意的是,所有的查詢變量在into關鍵字之后都不再可見,下面的例子就說明了這一點:

                  var query =
      from n1 in names
      select n1.ToUpper()
      into n2 //into之后只有n2可見
      where n1.Contains("x") //Error: n1不可見
      select n2;

      要理解其原因,我們只要看看它編譯器為它翻譯成對應的方法語法就能知曉:

                  var query = names
      .Select(n1 => n1.ToUpper())
      .Where(n2 => n1.Contains("x")); //Error: n1不再可見,lambda表達式中只有n2

      包裝查詢

      漸進式查詢創建方式可以通過在一個查詢中嵌入另一個查詢來改寫,這樣可以把多個查詢組合成單個查詢,即:

      var tempQuery = tempQueryExpr

      var finalQuery = from … in (tempQuery)

      可以改寫為:

      var query = from … in (tempQueryExpr)

      上面兩種方式以及into關鍵字的工作方式是一樣的,編譯器都會把他們翻譯成一個鏈接查詢運算符。請看下面的示例:

                  string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };

      // 漸進式查詢(Progressive query building)
      IEnumerable<string> query =
      from n in names
      select Regex.Replace(n, "[aeiou]", "");

      query = from n in query where n.Length > 2 orderby n select n;

      // 用包裝查詢方式進行改寫(Wrapping Queries)
      IEnumerable<string> query2 =
      from n1 in
      (
      from n2 in names
      select Regex.Replace(n2, "[aeiou]", "")
      )
      where n1.Length > 2
      orderby n1
      select n1;

      // 與上面等價的方法語法
      IEnumerable<string> query3 = names
      .Select(n => Regex.Replace(n, "[aeiou]", ""))
      .Where(n => n.Length > 2)
      .OrderBy(n => n);

       

      數據轉換

      LINQ中的數據轉換,也叫結果投影,是指LINQ查詢select的輸出。到目前為止,我們還只是看到了輸出單個標量元素的示例。通過使用對象初始化器,我們可以輸出更為復雜的結果類型。比如下面的示例,當我們在把姓名中的元音字母去掉之后,我還需要保存姓名的原始版本:

              class TempProjectionItem
      {
      public string Original;
      public string Vowelless;
      }

      static void TestProjectionStrategy()
      {
      string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };

      IEnumerable<TempProjectionItem> temp =
      from n in names
      select new TempProjectionItem
      {
      Original = n,
      Vowelless = Regex.Replace(n, "[aeiou]", "")
      };
      //我們可以繼續在結果中查詢
      IEnumerable<string> query =
      from item in temp
      where item.Vowelless.Length > 2 //按去除元音字母版本過濾
      select item.Original; //結果為姓名原始版本
      }

      匿名類型

      上面我們自己定義了類型TempProjectionItem來存放查詢的結果。通過使用匿名類型,我們可以省去這種中間類型的定義,而由編譯器來幫我們完成:

                  var intermediate = from n in names
      select new
      {
      Original = n,
      Vowelless = Regex.Replace(n, "[aeiou]", "")
      };
      IEnumerable<string> query = from item in intermediate
      where item.Vowelless.Length > 2
      select item.Original;

      需要注意的是,因為匿名類型的確切類型名是由編譯器自動產生的,因此intermediate的類型為:IEnumerable <random-compiler-produced-name> 。我們來聲明這種類型的唯一方式就是使用var關鍵字,這時,var不只是更加簡潔,而且也是必需的手段。

      let關鍵字

      let關鍵字讓我們可以在保持范圍變量的同時引入新的查詢變量。比如上面的示例,我們可以用let關鍵字作如下改寫:

                  string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
      var query = from n in names
      let Vowelless = Regex.Replace(n, "[aeiou]", "")
      where Vowelless.Length > 2
      select n; //正是因為使用了let,此時n仍然可見

      let關鍵字非常靈活和方便,就像例子看到的那樣。而且,我們可以使用多個let關鍵字,并且后面的 let表達式可以引用前一個let關鍵字引入的變量。

       

      本系列LINQ之路文章到此已經對LINQ to Objects進行了比較詳細的討論,接下去的打算是對解釋查詢(LINQ to SQL, LINQ to XML等)以及更多的查詢運算符進行討論和學習。希望系列文章能對閱者有些幫助,也期待大家的意見和提議^_^。

      posted @ 2011-10-31 13:21  Life a Poem  閱讀(17918)  評論(41)    收藏  舉報
      主站蜘蛛池模板: 欧美一区二区三区激情| 久热伊人精品国产中文| 欧美另类精品xxxx人妖| 国产线播放免费人成视频播放 | 国产不卡一区二区在线视频| 国产一区二区三区综合视频| 性欧美VIDEOFREE高清大喷水| 精品亚洲国产成人性色av| 樱花草视频www日本韩国| av一区二区中文字幕| 日韩精品 在线 国产 丝袜| 四虎国产精品永久入口| 色橹橹欧美在线观看视频高清| 亚洲精品成a人在线观看| 久热这里有精品免费视频| 亚洲女同性同志熟女| 亚洲男人av天堂久久资源| 中日韩黄色基地一二三区| 亚洲一区二区三区在线观看精品中文 | 另类国产精品一区二区| 亚洲2017天堂色无码| 九九热视频精选在线播放| 一道本AV免费不卡播放| 人人超碰人摸人爱| 日日摸天天爽天天爽视频| 久久久国产成人一区二区| 国产精品亚洲二区在线播放 | 精品国精品自拍自在线| 国产成人啪精品视频免费网 | 久久青青草原精品国产app| 久99久热精品免费视频| 国产福利深夜在线播放| 中文字字幕在线中文乱码| 中文字幕国产精品日韩| 成人永久免费A∨一级在线播放| AV人摸人人人澡人人超碰| 最新国产精品好看的精品| 亚洲成av人片一区二区| 黑人巨大videos极度另类| 色综合久久久久综合体桃花网| 国产一区二区三区导航|