初次使用C#中的yield

来源:http://www.cnblogs.com/xiao99/archive/2016/11/24/6098285.html
-Advertisement-
Play Games

這幾天在Python程式員的微信訂閱號中總是見到yield的關鍵字,才想起來在C#中也是有yield,但是只是知道有,從來沒有瞭解過他的用法,今天有時間就來看看是怎麼使用的。剛開始肯定就是搜索一下用法了,找到兩篇說明示例,一是 C# 中的"yield"使用,第二個是MSDN的官方api yield( ...


  這幾天在Python程式員的微信訂閱號中總是見到yield的關鍵字,才想起來在C#中也是有yield,但是只是知道有,從來沒有瞭解過他的用法,今天有時間就來看看是怎麼使用的。剛開始肯定就是搜索一下用法了,找到兩篇說明示例,一是 C# 中的"yield"使用,第二個是MSDN的官方api yield(C# 參考)

說實話第一個示例看完還是很模糊的概念,例子也沒有看懂是在幹嘛,一直到MSDN中給出結果集我才明白了到底的用法是怎麼樣的。

先來舉例一個需求: 一個方法返回一個IEnumerable 類型結果集(例如返回一個list<int>的結果),通常的代碼是這樣的

 

 1         /// <summary>
 2         /// 
 3         /// </summary>
 4         /// <returns></returns>
 5         public IEnumerable<int> Method()
 6         {
 7             List<int> results = new List<int>();
 8             int counter = 0;
 9             int result = 1;
10 
11             while (counter++ < 10)
12             {
13                 result = result * 2;
14                 results.Add(result);
15             }
16             return results;
17         }

這樣就完成了需求。

但是 有了yield之後就可以這樣寫了

 1         /// <summary>
 2         /// 
 3         /// </summary>
 4         /// <returns></returns>
 5         public IEnumerable<int> YieldDemo()
 6         {
 7             int counter = 0;
 8             int result = 1;
 9             while (counter++ < 10)
10             {
11                 result = result * 2;              
12                 yield return result;
13             }
14         }

兩種效果是一樣的,但是從我個人而言我喜歡第二個,感覺更簡潔一些。

題外話:在寫這兩個例子中我又增加了一個知識點

  返回值IEnumerable其實和IEnumerable<object>是等價的,只是IEnumerable的結果需要動態的解析; 

 

但是還搞不清楚這兩者實現有什麼區別,所以我想看看這兩個在做同一件事的時候效率如何,下麵來嘗試使用while迴圈10000000的取數據的耗時比較

使用 BenchmarkDotNet  測試結果如下

使用Stopwatch測試結果也是一樣的

從這個測試裡面可以看出YieldDemo方法幾乎沒有耗時,但是實際情況是不可能的吧,所以我又嘗試做了遍歷的測試

 

 1             Stopwatch stop = new Stopwatch();
 2             stop.Start();
 3             var res = new YieldTest().YieldDemo();
 4             foreach (var item in res)
 5             {
 6 
 7             }
 8             var a = stop.ElapsedMilliseconds;
 9             stop.Restart();
10 
11 
12             var rrrrr = new YieldTest().Method();
13             foreach (var item in rrrrr)
14             {
15 
16             }
17             var b = stop.ElapsedMilliseconds;
18             stop.Restart();

這個測試的結果是a=168,b=142.對比上一個測試結果讓我更加疑惑,我就開始打斷點,看看執行的順序是怎樣的。

結果如下:  

     在 第三行 斷點壓根就沒有進YieldDemo這個方法,而是當進行foreach 遍歷結果的時候,才開始進入了YieldDemo這個方法,更奇怪的是每次的foreach 都會進入YieldDemo的while一次去取數據

這個結果讓我有點懵了,只能再仔細看看文檔解析,

  迭代器方法運行到 yield return 語句時,會返回一個 expression,並保留當前在代碼中的位置。 下次調用迭代器函數時,將從該位置重新開始執行。 可以使用 yield break 語句來終止迭代。 

貌似這裡面是涉及到了迭代器的東西。馬上找迭代器的知識點,在 詳解C# 迭代器 中看到這樣一句解釋

  需要強調的一點是,對於迭代塊,雖然我們寫的方法看起來像是在順序執行,實際上我們是讓編譯器來為我們創建了一個狀態機。這就是在C#1中我們書寫的那部分代碼---調用者每次調用只需要返回一個值,因此我們需要記住最後一次返回值時,在集合中位置。

  當編譯器遇到迭代塊時,它創建了一個實現了狀態機的內部類。這個類記住了我們迭代器的準確當前位置以及本地變數,包括參數

這句話貌似解析了上面的疑問,但是看的有點雲里霧裡,還要花時間消化一下裡面的具體原理 。

官方提示使用yield有一些限制,需要註意

1 不能將 yield return 語句置於 try-catch 塊中。 可將 yield return 語句置於 try-finally 語句的 try 塊中。
2 可將 yield break 語句置於 try 塊或 catch 塊中,但不能將其置於 finally 塊中。
3 如果 foreach 主體(在迭代器方法之外)引發異常,則將執行迭代器方法中的 finally 塊。
4 匿名方法。 有關詳細信息,請參閱匿名方法。
5 包含不安全的塊的方法。 有關詳細信息,請參閱unsafe。

 

針對第一點讓我感覺使用好有限制,為啥不能在try-catch 中使用呢?

關於其他的一些使用方法在MSDN裡面都有詳細的講解,感覺沒有什麼好多說的。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • linux的特點 優點: 1、免費的/開源的系統 2、支持多線程/多用戶的系統 3、安全性好 4、對記憶體和文件管理優越 5、提供了豐富的網路功能 6、良好的用戶界面。圖形化界面和字元型界面 linux體積最少只需要記憶體4M,由於小所以可以做嵌入式開發 linux系統的組成: 內核:是系統的心臟,實現 ...
  • 若虛擬機在不正常關機的時候會遇到如下圖所示的問題:先點擊“取消”按鈕 解決方法:打開“資源管理器”,進入到彈出提示視窗所在的路徑(即H:\VMware\Virtual Machines Documents\CentOS),在這裡找到CentOS.vmx.lck文件夾,然後將尾碼名.lck的文件夾刪除 ...
  • 1.參照Zabbix文檔配置 依照官方文檔配置,沒什麼說的。 zabbix官方文檔:https://www.zabbix.com/documentation/3.2/manual/vm_monitoring 2.遇到的問題 這裡主要介紹我遇到的問題。由於理解偏差,文檔中的sdk,我以為是sdk的意思... ...
  • 問題 怎麼樣可以使用更貼近資源(Controller,Action)的方式定義路由。 解決方案 可以使用屬性路由直接在資源級別聲明路由。只要簡單的在 Action 上使用屬性路由 RouteAttribute,然後傳一個相關路由模板就可以。屬性路由與集中式路由在路由模板含義上基本是一樣的,所有路由參 ...
  • 在對ASP.NET Core管道中關於依賴註入的兩個核心對象(ServiceCollection和ServiceProvider)有了足夠的認識之後,我們將關註的目光轉移到編程層面。在ASP.NET Core應用中基於依賴註入的編程主要涉及到兩個方面,它們分別是將服務註冊到ServiceCollec... ...
  • 本月16號,MS發佈了 .NET Core 1.1。作為一個用貫MS產品的小盆友,我第一時間就把相關的安裝包下載下來了,然後果斷安裝(入坑)。 我猜你來看這篇博客可能遇到了和我一樣的問題。 問題0:正確的安裝順需 正確的順序在MS的dotnet Core官網上可以找到,請根據自己的VS版本對號入座。 ...
  • 本文版權歸博客園和作者吳雙本人共同所有,轉載和爬蟲請註明原文地址: www.cnblogs.com/tdws 寫在前面 在後臺介面開發中,介面文檔是必不可少的。在複雜的業務當中和多人對接的情況下,簡單的介面文檔又不能滿足需求,試想你的單應用後臺有幾十個模塊,幾百甚至更多的介面,又有上百個ViewMo ...
  • 一、ASP.NET 中的 Web API [水煮 ASP.NET Web API2 方法論](1-1)在MVC 應用程式中添加 ASP.NET Web API 與 ASP.NET MVC 在同一個進程中使用 ASP.NET WEB API [水煮 ASP.NET Web API2 方法論](1-2) ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...