C# 7.0 新特性2: 本地方法

来源:http://www.cnblogs.com/ylvict/archive/2016/06/13/5579350.html
-Advertisement-
Play Games

本文參考Roslyn項目中的Issue:#259. 1. C# 7.0 新特性1: 基於Tuple的“多”返回值方法 簡而言之,【本地方法】就是在方法體內部定義一個方法。 其實咋眼一看,這個新特新並沒有什麼新意,因為目前大量C#的項目中,都可以使用delegate或基於delegate變形的各種方案 ...


本文參考Roslyn項目中的Issue:#259.

  1. C# 7.0 新特性1: 基於Tuple的“多”返回值方法

 

簡而言之,【本地方法】就是在方法體內部定義一個方法

其實咋眼一看,這個新特新並沒有什麼新意,因為目前大量C#的項目中,都可以使用delegate或基於delegate變形的各種方案(lambda, Fun<*>, Action, Action<*> ...)。

但是請仔細推敲一下,方法體內部delegate,是否真的那麼完美無缺……

 

目前的C#

我們看一下,通常方法內部設置子邏輯單元的做法。

1 public void Bar()
2 {
3     var arr= new int[] { 5,8 ,10, 20 };
4     Func<int, string> handler = i => $"當前值是:{i}。"; 
5     foreach (var i in arr)
6     {
7         Console.WriteLine(handler(i));
8     }
9 }

看起來有什麼問題嗎?當然,很多。

  1. 首先,handler是無法進行遞歸調用的,看下麵的代碼。

1 public int Bar(int n)
2 {
3     if (n < 0) throw new ArgumentException();
4     Func<int, int> handler = n => {
5         if (n == 0) return 1;
6         return n * handler(n - 1);
7     };
8     return handler(n);
9 }

  這時handler(n-1) 的調用會報錯(Use of unassigned local variable 'handler'),原因是handler還未被賦值。通常,這種問題我們會嘗試用一種非常難看的做法變通解決:

1 Func<int, int> handler = null;
2 handler = n =>{
3     if (n == 0) return 1;
4     return n * handler(n - 1);
5 };

  咳咳咳,不多說了,心裡一萬隻羊駝狂奔而過。

  2. 其次,Lambda表達式的使用,非常有局限,它不允許在參數中添加行為修飾 out, ref, params, 以及可選參數,均不能在Lambda表達式的參數表中出現。參數無法使用泛型。

  3. 分配了一個委托對象來指向函數,為了能夠在Lambda表達式中訪問本地變數,會為其分配一個新的對象,間接的增加了GC的壓力。

 

說到這裡,可能有的童鞋會自然的想到更原始的解決方案,在外部聲明一個私有函數,就不會存在以上一系列的問題。

 1 class Foo
 2 {
 3     public void Bar(int[] arr)
 4     {
 5         foreach(var i in arr)
 6         {
 7             Console.WriteLine(Handler(i));
 8         }
 9     }
10     
11     private string Handler(int i) =>  $"當前值是:{i}";
12 }

這的確是一種簡單粗暴的解決方案,但是依然存在一些小問題,一個僅在Bar方法中有引用的方法,邏輯上也沒必要暴露給this的其他成員。這種做法其實是結構上的一種不合理。

 

本地方法(Local Function)

在C#7.0中,允許代碼直接在一個方法體(方法,構造,屬性的Getter和Setter)里聲明並調用子方法。

廢話不說,上代碼:

 1 public void Bar(int[] arr)
 2 {
 3     var length = arr.Length;
 4     string Length() {
 5         return $"length is {length}";
 6     }
 7     //或:
 8     //string Length() => $"length is {length}";
 9     Length();
10 }

上面例子中的Length(),在編譯後會轉化成當前類的私有成員方法(IL: this.<Bar>g__Length(): string()),但由於在C#語言層面做出了限制,只被允許在Bar方法中訪問。

由於對this而言,是以類似匿名方法的形態存在,所以,在當前類中仍然可以定義同名且同樣聲明的成員方法,從所在的方法體中調用,會執行本地方法。

Okay,話說回來,由於它的本質成員方法,所以它可以避免 [委托 / Lambda表達式] 的種種限制,可以非同步,可用泛型,可用out, ref, param, 可以yield, 特性參數, 等等。。

來個例子:

 1 class Foo
 2 {
 3     public IEnumerable<T> Bar<T>(params T[] items)
 4     {
 5         if (items == null) throw new ArgumentException(nameof(items));
 6 
 7         IEnumerable<T2> Enumerate<T2> ([CallerMemberName] T2[] array) //使用泛型及特性參數
 8         {
 9             //本地方法邏輯
10             foreach (var item in array)
11             {
12                 yield return item; //使用迭代器
13             }
14         }
15 
16         return Enumerate<T>(items); //調用本地方法
17         //return this.Enumerate<T>(items);  //調用成員方法
18     }
19 
20     IEnumerable<T2> Enumerate<T2>([CallerMemberName] T2[] array)
21     {
22         //成員方法邏輯
23     }
24 }

 

總結

這個feature可以看出,C#在朝著函數式語言謹慎的調整。回想起很多人在首次接觸代碼的懵懂期,經常犯一種比較低級的錯誤,傻傻的嘗試在Main方法中寫函數聲明,現在看來,那才是最直接的思維邏輯。

 

目前(2016年6月)C#7.0還未正式發佈,大家如果想體驗部分特性,可以去下載VS15預覽版,最終發佈的語法可能和本文中提及的有說不同,最新動態請大家關註Roslyn項目。


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

-Advertisement-
Play Games
更多相關文章
  • 將oledb讀取的excel數據快速插入的sqlserver中,很多人通過迴圈來拼接sql,這樣做不但容易出錯而且效率低下,最好的辦法是使用bcp,也就是System.Data.SqlClient.SqlBulkCopy 類來實現。不但速度快,而且代碼簡單,下麵測試代碼導入一個6萬多條數據的shee ...
  • 這個問題來自論壇提問,同理可以獲得access等資料庫的表結構信息。 推薦:http://www.cnblogs.com/roucheng/p/excelhanshu.html ...
  • 首先要瞭解對方網頁的運行機制 ,這可以用httpwacth或者httplook來看一下http發送和接收的數據。這兩個工具應該說是比較簡單易懂的。這裡就不再介紹了。主要關註的內容是header和post的內容。一般會包括cookie,Referer頁面和其他一些亂其八糟可能看不懂的變數,還有就是正常 ...
  • 在WCF4.0里,通過提供一種虛擬的服務類型映射機制來實現WCF服務的激活。我們可以在配置文件里指定服務類型和相對地址之間的映射關係。這就使得我們可以在不是要.svc文件的情況下,在WAS/IIS里托管WCF服務程式。 ...
  • <esri:InfoWindow x:Name="InfoWinMF" Placement="TopRight" Padding="15" Map="{Binding ElementName=mainmap}" ContentTemplate="{StaticResource GeneralData ...
  • Lambda表達式 簡化了匿名委托的使用,讓你讓代碼更加簡潔,優雅。據說它是微軟自c#1.0後新增的最重要的功能之一。 首先來看一下其發展 根據上面的發展歷程,可以感到Lambda表達式愈加簡化。 詳細介紹: ...
  • 回到目錄 關於邏輯刪除 對於邏輯刪除之前的做法是在實體類中加個欄位,一般是status,其中一種狀態是刪除,當然也有其它做法,如加個bool的欄位IsDeleted,這些其實都過於武斷,即它在基類裡加上後,所以實體類都會有這種特性,而對於現實的數據表,可能不顯示這種邏輯刪除的特性,如關係表,日誌表, ...
  • 背水一戰 Windows 10 之 動畫: PopInThemeAnimation - 控制項出現時的動畫, PopOutThemeAnimation - 控制項消失時的動畫, FadeInThemeAnimation - 控制項淡入的動畫, FadeOutThemeAnimation - 控制項淡出的動畫... ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...