<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C#.NET 拾遺補(bǔ)漏:理解 yield 關(guān)鍵字

          共 2312字,需瀏覽 5分鐘

           ·

          2021-12-10 10:39

          在 C# 代碼中,尤其是基礎(chǔ)庫(kù)的 API 中,我們經(jīng)??梢钥吹胶芏喾椒ǚ祷氐氖?IEnumerable 類型,為什么要返回 IEnumerable 而不是 IList、ICollection 等類型呢?從字面上理解,IEnumerable 表示該集合中的元素可以被遍歷。要完全理解 IEnumerable 類型對(duì)象如何被遍歷,就要先理解 yield 關(guān)鍵字。

          在 C# 中,大多數(shù)方法都是通過(guò) return 語(yǔ)句把計(jì)算得到的結(jié)果返回給調(diào)用者,同時(shí)把控制權(quán)交回給調(diào)用者。比如下面這樣一個(gè)獲取斐波那契數(shù)列的方法:

          IEnumerable<int> nums = Fibonacci(10);
          foreach (var n in nums)
          {
          Console.Write("{0} ", n);
          }

          List<int> Fibonacci(int count)
          {
          int prev = 1;
          int curr = 1;
          List<int> result = new();
          for (int i = 0; i < count; i++)
          {
          result.Add(prev);
          int temp = prev + curr;
          prev = curr;
          curr = temp;
          }
          return result;
          }

          輸出:

          1 1 2 3 5 8 13 21 34 55

          Console.Write() 打印結(jié)果之前,變量 nums 已經(jīng)裝載了完整的數(shù)據(jù),所以運(yùn)行后在打印結(jié)果的時(shí)候可以瞬間把結(jié)果全部輸出,這看起來(lái)沒(méi)有什么問(wèn)題。

          現(xiàn)在換個(gè)場(chǎng)景,假設(shè) Fibonacci() 方法內(nèi)部每次計(jì)算得到下一個(gè)數(shù)都需要耗費(fèi)較長(zhǎng)的時(shí)間。我們用 Thread.Sleep() 模擬一下所需的耗時(shí),如下:

          ...
          for (int i = 0; i < count; i++)
          {
          result.Add(prev);
          ????Thread.Sleep(1000);
          int temp = prev + curr;
          prev = curr;
          curr = temp;
          }
          return result;
          }

          再次運(yùn)行,你會(huì)發(fā)現(xiàn),大概等待 10 秒后所有數(shù)字被瞬間打印出來(lái)。而在等待的這段時(shí)間,你無(wú)法了解程序運(yùn)算的進(jìn)展,期間是沒(méi)有反饋的。

          可以通過(guò) yield 關(guān)鍵字很好地解決這個(gè)問(wèn)題。yield 可以把每一步計(jì)算推遲到它程序?qū)嶋H需要的時(shí)候再執(zhí)行,也就是說(shuō),你不必等所有結(jié)果都計(jì)算完才執(zhí)行下文代碼。

          下面使用 yield 關(guān)鍵字改造一下 Fibonacci() 方法:

          IEnumerable<int> Fibonacci(int count)
          {
          int prev = 1;
          int curr = 1;
          for (int i = 0; i < count; i++)
          {
          yield?return prev;
          Thread.Sleep(1000);
          int temp = prev + curr;
          prev = curr;
          curr = temp;
          }
          }

          再次運(yùn)行后,你會(huì)看到,每隔 1 秒會(huì)輸出一個(gè)數(shù)字,直到所有數(shù)字全部輸出。雖然總的等待時(shí)間是一樣的,但對(duì)于圖形用戶界面來(lái)說(shuō),這種即時(shí)響應(yīng)的用戶體驗(yàn)明細(xì)要好于之前的“漫長(zhǎng)”等待。

          yield 關(guān)鍵字的用途是把指令推遲到程序?qū)嶋H需要的時(shí)候再執(zhí)行,這個(gè)特性允許我們更細(xì)致地控制集合每個(gè)元素產(chǎn)生的時(shí)機(jī)。它的好處之一是,可以像上面演示的那樣盡可能即時(shí)地給用戶響應(yīng)。還有一個(gè)好處是,可以提高內(nèi)存使用效率。當(dāng)我們有一個(gè)方法要返回一個(gè)集合時(shí),而作為方法的實(shí)現(xiàn)者我們并不清楚方法調(diào)用者具體在什么時(shí)候要使用該集合數(shù)據(jù)。如果我們不使用 yield 關(guān)鍵字,則意味著需要把集合數(shù)據(jù)裝載到內(nèi)存中等待被使用,這可能導(dǎo)致數(shù)據(jù)在內(nèi)存中占用較長(zhǎng)的時(shí)間。

          通過(guò) yield 返回的 IEnumerable 類型,表示這是一個(gè)可以被遍歷的數(shù)據(jù)集合。它之所以可以被遍歷,是因?yàn)樗鼘?shí)現(xiàn)了一個(gè)標(biāo)準(zhǔn)的 IEnumerable 接口。一般,我們把像上面這種包含 yield 語(yǔ)句并返回 IEnumerable 類型的方法稱為迭代器(Iterator)。

          注意:包含 yield 語(yǔ)句的方法的返回類型也可以是 IEnumerator,它比迭代器更低一個(gè)層級(jí),迭代器是列舉器的一種實(shí)現(xiàn)。

          迭代器方法和普通的方法相比,普通方法是通過(guò) return 語(yǔ)句立即把程序的控制權(quán)交回給調(diào)用者,同時(shí)也會(huì)把方法內(nèi)的本地(局部)資源釋放掉。迭代器方法則是在依次返回多個(gè)值給調(diào)用者的期間保留本地資源,等所有值都返回結(jié)束時(shí)再釋放掉本地資源,這些返回的值將形成一組序列被調(diào)用者使用。

          在 C# 中,迭代器可以用于方法、屬性或索引器中。迭代器中的 yield 語(yǔ)句分為兩種:

          • yeild return,把程序控制權(quán)交回調(diào)用者并保留本地狀態(tài),調(diào)用者拿到返回的值繼續(xù)往后執(zhí)行。

          • yeild break,用于告訴程序當(dāng)前序列已經(jīng)結(jié)束,相當(dāng)于正常代碼塊的 return 語(yǔ)句(迭代器中直接使用 return 是非法的)。

          實(shí)際場(chǎng)景中,我們一般很少直接寫(xiě)迭代器,因?yàn)榇蟛糠中枰膱?chǎng)景都是數(shù)組、集合和列表等,而這些類型內(nèi)部已經(jīng)封裝好了所需的迭代器。


          瀏覽 53
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲春色校园 | 国产内射视频在线观看 | xxxx成人av | 91干逼免费观看 | 国产a久久麻豆入口 |