C#7 特性預覽
在過去一年間,我們為讀者展示了多個已考慮加入C# 7中的特性。在最近釋出的Visual Studio 15預覽版中,微軟決定為使用者展現這些特性,使其成為C# 7最終釋出的一部分。
元組值型別
.NET提供了一個元組(Tuple)型別,但具體在C#中使用時卻存在著各種各樣的問題。由於元組型別是一個引用型別,因此在一些對於效能相當敏感的程式碼中,你很可能會避免因使用它而造成GC的開銷。同時,元組型別是不可變的,雖然這使跨執行緒共享變得更安全,但也意味著每次進行變更都必須分配一個新的物件。
為了應對這一問題,C# 7將提供一個值型別的元組。這是一個可變型別,對那些重視效能的程式碼來說,這種方式將更為高效。同時,作為值型別,它在每次進行分配時都會生成一個拷貝,因此幾乎沒有產生多執行緒問題的風險。
你可以通過以下語法建立一個元組:
var result = (5, 20);
你也可以選擇對元組中的值進行命名,這一點並不是必須的,只是讓程式碼具有更好的可讀性。
var result = (count: 5, sum: 20);
你可能會想,“很棒的特性,但我自己也能寫得出來”。但下一個特性才是重頭戲。
多返回值
在類C風格的語言中,要在一個函式中返回兩個值始終是一件麻煩事。你只能選擇將結果封裝成某種結構,或是使用輸出引數。與許多函數語言程式設計語言一樣,C#選擇了第一種方式為你提供這一特性:
(int, int) Tally (IEnumerable<int> list)
可以看到,在這裡使用泛用的元組有一個基本問題:我們將無從得知每個欄位的作用。因此,C#選擇通過一個編譯器花招對結果進行命名:
(int Count, int Sum) Tally (IEnumerable<int> list)
我們在此需要強調一點:C#並沒有生成一個新的匿名型別,你所獲得的仍舊是一個元組,但編譯器將假設它的屬性為Count和Sum,而不是Item1和Item2。所以,以下程式碼行的作用都是等價的:
var result = Tally(list); Console.WriteLine(result.Item1); Console.WriteLine(result.Count);
請注意一點,我們現在還不具備多賦值語法,如果這種語法最終實現,那麼它的用法可能是這樣的:
(count, sum) = Tally(list);
除了提供簡單的功能性函式之外,多返回值的實用性還體現在非同步程式碼的編寫上,因為在async函式中是不允許使用out引數的。
模式匹配:改進的Switch語法塊
VB與函式式程式設計師對於C#抱怨得最多的一點就是C#中的switch語句功能十分有限。VB開發者希望能夠進行範圍匹配,而習慣了F#或Haskell的開發者則希望能夠使用分解式的模式匹配。C#打算同時提供這兩種特性。
在對型別進行模式匹配時,你可以建立一個變數以儲存轉型的結果。舉例來說,在對一個System.Object使用switch語句時,你可以編寫以下程式碼:
case int x:
如果該物件是數值型別,則變數x將得以賦值。否則的話,程式將按從上至下的順序檢查下一個case語句塊。如果你想更具體地進行匹配,還可以使用範圍檢查:
case int x when x > 0: case int y:
在這個示例中,如果該物件是正整數,則x程式碼塊將被執行。如果物件是0或負整數,而y程式碼塊將被執行。
如果需要檢查null值,則只需使用以下語法:
case null;
模式匹配:分解
目前為止,我們僅僅展示了某種對VB中已有的特性所做的增量式改進,而模式匹配真正的強大之處在於分解,它可以將某個物件完全拆開,考慮一下以下語法:
if (person is Professor {Subject is var s, FirstName is "Scott"})
這段程式碼完成了兩件事:
- 它建立了一個本地變數s,將其賦值為((Professor)person).Subject。
- 它執行了一次相等性檢查 ((Professor)person).FirstName == "Scott"。
如果將其用C# 6程式碼改寫則是這樣:
var temp = person as Professor; if (temp != null && temp.FirstName == "Scott") { var s = temp.Subject
在最終釋出中,我們預計能夠同時看到對switch語句塊的這兩種改進。
引用返回
對於大資料結構進行引用傳遞比起值傳遞要快得多,因為後者需要對整個結構進行拷貝。與之類似,返回一個大資料結構的引用一樣能夠提升速度。
在類似於C這樣的語言中,可以通過指標返回某個結構的引用。這種方式會帶來一個常見的問題,即指標所指向的記憶體可能會因為某種原因而已經被回收了。
C#通過使用引用的方式迴避這一問題,引用本身是一個附加了規則的指標。最重要的一條規則是,你不能夠返回某個本地變數的引用。如果你嘗試這樣做,那麼該變數所引用的棧資訊在函式返回時就已經變得不可訪問了。
在微軟的展示程式碼中,它所返回的引用指向一個陣列中的某個結構。由於它實質上是指向陣列中某個元素的指標,因此隨後可以對陣列本身進行修改。舉例來說:
var x = ref FirstElement(myArray) x = 5; //MyArray[0] now equals 5
這一語法的用例是對效能高度敏感的程式碼,在大多數應用中都無需使用這一特性。
二進位制字面值(Binary Literals)
此次釋出還引入了一個小特性,即二進位制字面值。這一語法只是一個簡單的字首而已,例如5可以表示為“0b0101”。這一特性的主要用例是設定基於flag的列舉,以及建立位掩碼(bitmask),以用於與C風格語言的互操作。
本地函式
本地函式是指在另一個函式中所定義的函式。第一眼看來,本地函式似乎只是比匿名函式稍好的一種語法。但它實際上還存在幾個優點:
- 首先,你無需為其分配一個委託以儲存該函式。這不僅減少了記憶體壓力,同時還允許編譯器對該函式進行內聯操作。
- 其次,在建立閉包時,也無需為其分配一個物件,因為它能夠直接訪問本地變數。這一點同樣能夠改善效能,因為它也減少了GC的壓力。
按照第二條規則推算,你將無法建立一個指向本地函式的委託。這一點對於程式碼的組織其實是一個優點,因為你無需建立獨立的函式,並且將現有函式的狀態作為顯式的引數進行傳遞。
部分類的改進
最後演示的特性是一種處理部分類的新方式。在過去,部分類的應用是基於程式碼生成優先的概念而出現的。所生成的程式碼將包含一系列部分方法,開發者可以選擇實現這些方法,以調整類的行為。
通過新的“replace”語法,開發者就多了一種新選擇,能夠以最直接的方式編寫程式碼,隨後再引入程式碼生成器,並重寫這些方法。以下將通過一個簡單的示例表現開發者的程式碼編寫方式:
public string FirstName {get; set;}
簡單又清晰,但完全不符合XAML風格應用的寫法。因此,程式碼生成器將生成如下程式碼:
private string m_FirstName; static readonly PropertyChangedEventArgs s_FirstName_EventArgs =new PropertyChangedEventArgs("FirstName") replace public string FirstName { get { return m_FirstName; } set { if (m_FirstName == value) return; m_FirstName = value; PropertyChanged?.Invoke(this, m_FirstName_EventArg); }
通過“replace”關鍵字,所生成的程式碼將直接替換手寫的程式碼,新增所缺失的功能。在這個示例中,我們甚至還能夠處理一些開發者經常會忽略的麻煩的部分,例如對EventArgs物件進行快取。
雖然這個官方示例僅用於屬性變更通知,但這一技術還可用於各種“面向切面程式設計(AOP)”的場景,例如在程式碼中注入日誌記錄、安全檢查、引數校驗以及其他各種繁瑣的樣板式程式碼。
如果讀者想實際瞭解一下這些特性,可以觀賞Channel 9中的視訊“The Future of C#”。
相關文章
- Swift 4.2 新特性預覽Swift
- Swift5 新特性預覽Swift
- Vue.js 3.0 新特性預覽Vue.js
- JFreeReport 0.9 的特性預覽
- Git 2.1釋出:新特性預覽Git
- 【譯】C# 11 特性的早期預覽C#
- look look C#7C#
- 最全的Vue3.0新特性預覽(翻譯)Vue
- maven工程指定版本號並開啟預覽特性Maven
- C#6,C#7,V#8,C#9 的新特性總結C#
- Vue 2.5釋出 代號Level E 新特性預覽Vue
- 炫酷報表工具 FineReport 9.0新特性預覽
- Win10 Build 18234新預覽版釋出 新特性一覽Win10UI
- Oracle 21c新特性預覽與日常管理相關的幾個新特性Oracle
- Swift 5 新特性預覽(最低支援Xcode 10.2 beta版)SwiftXCode
- Swoole v5.0 版本新特性預覽之新的執行模式模式
- Python 3.7 測試預覽版已經發布,新增新特性Python
- html預覽HTML
- Android O開發者預覽版終於推出啦!官方介紹新特性Android
- kkFileView預覽檔案 指定預覽方式為pdfView
- MongoDB 5.0新特性概覽MongoDB
- Swift 4.1 新特性概覽Swift
- MySQL 8.0新特性概覽MySql
- MongoDB 3.0新增特性一覽MongoDB
- Flutter Beta 3 新特性概覽Flutter
- MySQL5.7.6新特性一覽MySql
- Netscape 6.1特性概覽 (轉)
- Mac預覽工具使用技巧,Mac預覽功能實用技巧大全Mac
- Mac預覽工具使用教程,Mac預覽功能實用技巧大全Mac
- html 預覽-atomHTML
- 前端圖片預覽前端
- Android 附件預覽Android
- 純前端文件預覽前端
- html中線上預覽pdf檔案之pdf線上預覽外掛HTML
- .NET 6 預覽版 7 釋出——最後一個預覽版
- “低程式碼”平臺特性概覽
- golang1.16新特性速覽Golang
- Redis 7.0 新功能新特性總覽Redis