<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 原則8:優先考慮查詢語法(query syntax)而不是循環結構 **By D.S.Qiu** 尊重他人的勞動,**支持原創,轉載請注明[出處](/blog/1982137):[http://dsqiu.iteye.com](http://dsqiu.iteye.com)** C# 語言對不同控制結構都不乏支持: for , while , do/while 和 foreach ,所有都是語言的一部分。從過去的計算機語言設計來看,很難不讓人懷疑語言的設計者不是錯過某些驚奇的循環結構。實際上,總是存在一個更好的方法:查詢語法(query syntax)。 查詢語法可以讓你的程序邏輯從必要模式(imperative model)變為聲明模式(declarative model)。查詢語法定義了答案是什么而且決定了怎樣得到這個答案的特殊實現。上面說到的整個點,這里指的是查詢語法,方法調用語法帶來的好處查詢語句一樣有。這點對于查詢語句很重要,而且進一步擴展,方法語法實現查詢表達模式,比 imperative 循環結構更加清晰表達你的意圖。 這段代碼用必要的方法填充數值然后打印內容到控制臺: ``` int[] foo = new int[100]; for (int num = 0; num < foo.Length; num++) foo[num] = num * num; foreach (int i in foo) Console.WriteLine(i.ToString()); ``` 即使上面的例子很小,但過于重視操作如何執行而不是什么操作執行。使用查詢語法重新創建更可讀的代碼可以重復利用不同的編譯塊。 首先第一步,你使用查詢結果改變數組的產生: ``` int[] foo = (from n in Enumerable.Range(0, 100) select n * n).ToArray(); ``` 第二個循環你只要做類似的改動,盡管你需要寫一個擴展方法對每個元素執行操作: ``` foo.ForAll((n) => Console.WriteLine(n.ToString())); ``` .NET BCL 使用 List&lt;T&gt; 實現 ForAll 。這只是簡單地創建 IEnumerable&lt;T&gt; : ``` public static class Extensions { public static void ForAll<T>( this IEnumerable<T> sequence, Action<T> action) { foreach (T item in sequence) action(item); } } ``` 這可能看起來沒有意義,但是它更加能重復利用。任何你對數組元素的操作, ForAll 都能做到。 這個例子很簡單,所以你不會看到很多好處。實際,你也許是對的。我們接著看其他不同問題。 很多問題要求你通過嵌套循環來完成。假設你需要從0到99產生所有(x,y)對。很明顯你會使用嵌套循環: ``` private static IEnumerable<Tuple<int, int>> ProduceIndices() { for (int x = 0; x < 100; x++) for (int y = 0; y < 100; y++) yield return Tuple.Create(x, y); } ``` 當然,使用查詢你可以產生相同的對象: ``` private static IEnumerable<Tuple<int, int>> QueryIndices() { return from x in Enumerable.Range(0, 100) from y in Enumerable.Range(0, 100) select Tuple.Create(x, y); } ``` 看起來很相似,但是查詢更加簡單即使這個問題的描述變得更困難起來。改變問題為產生的(x,y)對要求x和y的和小于100。比較這兩個方法: ``` private static IEnumerable<Tuple<int, int>> ProduceIndices2() { for (int x = 0; x < 100; x++) for (int y = 0; y < 100; y++) if (x + y < 100) yield return Tuple.Create(x, y); } private static IEnumerable<Tuple<int, int>> QueryIndices2() { return from x in Enumerable.Range(0, 100) from y in Enumerable.Range(0, 100) where x + y < 100 select Tuple.Create(x, y); } ``` 仍然很相近,但是 imperative 語法開始使用必須的語法產生結果而隱藏它的意義。所以再次改變問題。現在,條件一個條件:返回的數組必須按照它們到原點的距離排列。 ``` private static IEnumerable<Tuple<int, int>> ProduceIndices3() { var storage = new List<Tuple<int, int>>(); for (int x = 0; x < 100; x++) for (int y = 0; y < 100; y++) if (x + y < 100) storage.Add(Tuple.Create(x, y)); storage.Sort((point1, point2) => (point2.Item1*point2.Item1 + point2.Item2 * point2.Item2).CompareTo( point1.Item1 * point1.Item1 + point1.Item2 * point1.Item2)); return storage; } private static IEnumerable<Tuple<int, int>> QueryIndices3() { return from x in Enumerable.Range(0, 100) from y in Enumerable.Range(0, 100) where x + y < 100 orderby (x*x + y*y) descending select Tuple.Create(x, y); } ``` 有些細節很明顯改變了。 imperative 版本更難去理解。如果你看得快,你幾乎不會注意到比較函數的參數被對換了。那樣保證排序的結果是降序的。沒有注釋或其他支持文檔, imperative 代碼很是很難讀懂。 即使你發現 where 的參數被對換了,你會覺得這是錯誤么? imperative 模式過于強調操作怎么樣執行以至于很容易在這些操作中迷失什么操作正在完成的原意。 還有一個理由使用查詢語法而不是循環結構:查詢可以比循環結構創建更多組合的 API 。查詢運費很自然構造算法塊執行序列上的操作。查詢的模式可以讓開發者枚舉序列中組合單一的操作為的組合操作。循環結構不能有類似的組合。你必須臨時存儲每步的結果,或創建對序列上組合操作的方法。 上個例子就體現了這點。操作組合自 一個過濾操作(where塊),一個排序操作(sort塊)和一個選擇操作select塊)。這些操作全部在一個枚舉操作完成。 imperative 版本創建歷史存儲模型而且排序操作被分離出來。 我幾經討論過查詢語法,但是你應該記住每個查詢操作都有相應的方法調用語法。有時候查詢語法更自然,有時候方法調用語法語法更自然。在上面例子,查詢語法更加可讀。下面是對應的方法調用語法: ``` private static IEnumerable<Tuple<int, int>> MethodIndices3() { return Enumerable.Range(0, 100). SelectMany(x => Enumerable.Range(0,100), (x,y) => Tuple.Create(x,y)). Where(pt => pt.Item1 + pt.Item2 < 100). OrderByDescending(pt => pt.Item1* pt.Item1 + pt.Item2 * pt.Item2); } ``` 查詢語法或方法調用語法哪個更加可讀是一個風格問題。在這個例子,我相信查詢語法是更清晰的。然而,其他例子可能會不同。此外,一些方法是沒有對應的查詢語法的。向 Take , TakeWile , Skip ,SkipWhile , Min ,和 Max 在一定程度上需要你使用方法語法。其他語言,特別是 VB.NET 定義了更多查詢語法的關鍵字。 有的人老是會認為我們討論的這部分即查詢的性能會比循環更慢。雖然你可以用一個簡單例子說明循環能跑贏查詢,但這不是一般地規則。如果你有一個特別的例子即查詢結果表現的不夠好,你才需要決定測量性能。然而,在你完成重寫一個算法之前,考慮使用 LINQ 的并行擴展。使用查詢語法的另一個好處是使用 .AsParallel() 方法可以并行執行查詢。(查看原則35)。 C#開始是一個 imperative 語言。它幾下保留了屬于這個遺產的所有特性。自然你可隨意使用最熟悉的工具(循環結構)。然而,這些工具可能不是最好的工具。當你發現你自己寫著循環結構的形式,問下自己是否使用查詢來寫。如果查詢語法不行,考慮使用函數調用語法。在大多數情況,你會發現創建比使用 imperative 循環結構更清晰的代碼。 小結: 這篇文章講的點還是比較好的,至少是一種新的編程模式(對于像D.S.Qiu這樣的人來說),可以嘗試多使用些,會帶來一些便利。本來一直很糾結 imperative model 和 declararive model 的中文翻譯,由于對計算機語言的歷史都不了解,對一些專業名稱很沒有太多認識,甚至都沒有怎么接觸,只有困惑來了就去看下 wikipedia 。每天都是到這個時候才寫完,脖子今天一直很不舒服,不要有頸椎病呀,完了。 歡迎各種不爽,各種噴,寫這個純屬個人愛好,秉持”分享“之德! 有關本書的其他章節翻譯請[點擊查看](/category/297763),轉載請注明出處,尊重原創! 如果您對D.S.Qiu有任何建議或意見可以在文章后面評論,或者發郵件(gd.s.qiu@gmail.com)交流,您的鼓勵和支持是我前進的動力,希望能有更多更好的分享。 轉載請在**文首**注明出處:[http://dsqiu.iteye.com/blog/1982137](/blog/1982137) 更多精彩請關注D.S.Qiu的博客和微博(ID:靜水逐風)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看