使用现代化 C# 语法简化代码
使用現代化 C# 語法簡化代碼
Intro
最近幾個版本的 C# 在語法中有很多的變化,有很多語法能夠幫助我們大大簡化代碼復雜度,使得代碼更加簡潔,分享幾個我覺得比較實用的可以讓代碼更加簡潔的語法
Default literal expressions
在 C# 7.1 之后,我們可以使用 default 來代替一個類型的默認值,例如:
public?void?Test(string?str?=?deault){}string?str?=?default;在之前的版本我們需要顯式指定類型,如 default(string),就不需要寫類型了,編譯器會推斷出類型
Target-Typed New Expression
在 C# 9 中,引入了 Target-Typed New Expression 語法,和上面的 default 類似,我們在創建對象的時候不再需要在編譯器可以推斷出類型的地方再寫出類型了,這在有時候會很有用,尤其是在寫一個類型非常復雜的字段的時候,我們就只需要聲明一次就可以了,可以參考下面的示例:
//?target-typed?new?expression //private?static?readonly?Dictionary<string,?Dictionary<string,?string>> //????Dictionary?=?new?Dictionary<string,?Dictionary<string,?string>>(); private?static?readonly?Dictionary<string,?Dictionary<string,?string>>Dictionary?=?new();//?array ReviewRequest[]?requests?= {new(){State?=?ReviewState.Rejected},new(),new(), };Named Tuple
從 C# 7 開始,我們可以使用 Named Tuple 來優化 Tuple 的使用,在之前的版本我們只能 Item1, Item2 這樣去使用 Tuple 的 Value,但是這樣很不好理解,尤其是在沒有文檔說明的情況下,可能每次都要去返回值的地方看一下究竟每一個元素代表什么,Named Tuple 出現了之后就相當于一個強類型的 Tuple,能夠使得代碼更好理解,tuple 元素的含義一目了然,舉個栗子:
(string?Alpha,?string?Beta)?namedLetters?=?("a",?"b"); Console.WriteLine($"{namedLetters.Alpha},?{namedLetters.Beta}");(int?code,?string?msg)?result?=?(1,?"");private?static?(int?code,?string?msg)?NamedTuple() {return?(0,?string.Empty); }var?result?=?NamedTuple(); Console.WriteLine(result.code);Deconstruct
與 Named Tuple 同時出現的,我們可以在類中聲明一個 Deconstruct 與 Constructor 相對應,只是 Constructor 是輸入參數, Deconstruct 是輸出參數,來看一個示例吧:
public?class?Point {public?Point(double?x,?double?y)=>?(X,?Y)?=?(x,?y);public?double?X?{?get;?}public?double?Y?{?get;?}public?void?Deconstruct(out?double?x,?out?double?y)?=>(x,?y)?=?(X,?Y); }var?p?=?new?Point(3.14,?2.71); (double?X,?double?Y)?=?p;上面的示例是官方文檔的一個示例,來看一個我們實際在用的一個示例吧:
public?class?IdNameModel {public?int?Id?{?get;?set;?}public?string?Name?{?get;?set;?}public?void?Deconstruct(out?int?id,?out?string?name){id?=?Id;name?=?Name;} }多個返回值時,有的數據不關心可以使用 “_” 來表示丟棄返回值,示例如下:
using?System; using?System.Collections.Generic;public?class?Example {public?static?void?Main(){var?(_,?_,?_,?pop1,?_,?pop2)?=?QueryCityDataForYears("New?York?City",?1960,?2010);Console.WriteLine($"Population?change,?1960?to?2010:?{pop2?-?pop1:N0}");}private?static?(string,?double,?int,?int,?int,?int)?QueryCityDataForYears(string?name,?int?year1,?int?year2){int?population1?=?0,?population2?=?0;double?area?=?0;if?(name?==?"New?York?City"){area?=?468.48;if?(year1?==?1960){population1?=?7781984;}if?(year2?==?2010){population2?=?8175133;}return?(name,?area,?year1,?population1,?year2,?population2);}return?("",?0,?0,?0,?0,?0);} } //?The?example?displays?the?following?output: //??????Population?change,?1960?to?2010:?393,149Pattern-Matching
模式匹配最早開始于 C# 7.1,最早的形式如:if(a is string str),這是最簡單也是最經典的一個模式匹配,它結合了之前需要兩句話才能完成的功能,可以翻譯成:
var?str?=?a?as?string; if(str?!=?null)?//...除了 if,我們在 switch 里也可以使用模式匹配的
void?SwitchPattern(object?obj0) {switch?(obj0){case?string?str1:Console.WriteLine(str1);break;case?int?num1:Console.WriteLine(num1);break;} }在 C# 9 中引入了邏輯運算符 and/or/not 使得模式匹配更為強大,來看一個判斷是否是合法的 Base64 字符的一個方法的變化:
C# 9 之前的代碼:
private?static?bool?IsInvalid(char?value) {var?intValue?=?(int)value;if?(intValue?>=?48?&&?intValue?<=?57)return?false;if?(intValue?>=?65?&&?intValue?<=?90)return?false;if?(intValue?>=?97?&&?intValue?<=?122)return?false;return?intValue?!=?43?&&?intValue?!=?47; }使用 C# 9 增強的模式匹配之后的代碼:
private?static?bool?IsInvalid(char?value) {var?intValue?=?(int)value;return?intValue?switch{>=?48?and?<=?57?=>?false,>=?65?and?<=?90?=>?false,>=?97?and?<=?122?=>?false,_?=>?intValue?!=?43?&&?intValue?!=?47}; }是不是一下子清晰的很多~~
Switch Expression
Switch Expression 是 C# 8 引入的新特性,C# 9 有結合模式匹配做了進一步的增強,使得其功能更加強大,來看示例吧:
修改前的代碼是這樣的:
var?state?=?ReviewState.Rejected; var?stateString?=?string.Empty; switch?(state) {case?ReviewState.Rejected:stateString?=?"0";break;case?ReviewState.Reviewed:stateString?=?"1";break;case?ReviewState.UnReviewed:stateString?=?"-1";break; }使用 switch expression 之后的代碼如下:
var?state?=?ReviewState.Rejected; var?stateString?=?state?switch {ReviewState.Rejected?=>?"0",ReviewState.Reviewed?=>?"1",ReviewState.UnReviewed?=>?"-1",_?=>?string.Empty };是不是看起來簡潔了很多,還有進一步的增加優化,來看下一個示例:
(int?code,?string?msg)?result?=?(0,?""); var?res?=?result?switch {(0,?_)?=>?"success",(-1,?_)?=>?"xx",(-2,?"")?=>?"yy",(_,?_)?=>?"error" }; Console.WriteLine(res);猜猜不同情況的輸出的結果是什么樣的,再自己試著跑一下結果看看是不是符合預期吧
Index Range
Index/Range 是 C# 8 引入的一個新特性,主要優化了對元組的操作,可以更方便的做索引和切片操作
之前有過一篇詳細的介紹文章,可以參考:C# 使用 Index 和 Range 簡化集合操作
我們可以通過 ^(hat) 操作符來反向索引數組中的對象,可以通過 .. 來創建一個集合的子集合,來看一個簡單的示例:
var?arr?=?Enumerable.Range(1,?10).ToArray(); Console.WriteLine($"last?element:{arr[^1]}");var?subArray?=?Enumerable.Range(1,?3).ToArray(); Console.WriteLine(arr[..3].SequenceEqual(subArray)???"StartWith"?:?"No");Record
Record 是 C# 9 引入的新特性,record 是一個特殊的類,編譯器會幫助我們做很多事情,會自動實現一套基于值的比較,而且可以很方便實現對象復制的功能,詳細介紹可以參考之前的 record 介紹文章 C# 9 新特性 — record 解讀,可以看下面這個簡單的示例:
public?abstract?record?Person(string?FirstName,?string?LastName); public?record?Teacher(string?FirstName,?string?LastName,?int?Grade):?Person(FirstName,?LastName); public?record?Student(string?FirstName,?string?LastName,?int?Grade):?Person(FirstName,?LastName); public?static?void?Main() {Person?teacher?=?new?Teacher("Nancy",?"Davolio",?3);Person?student?=?new?Student("Nancy",?"Davolio",?3);Console.WriteLine(teacher?==?student);?//?output:?FalseStudent?student2?=?new?Student("Nancy",?"Davolio",?3);Console.WriteLine(student2?==?student);?//?output:?True }Top-Level Statement
Top-Level statement 是 C# 9 支持的新特性,我們可以不寫 Main 方法,直接寫方法體,對于一些比較簡單的小工具,小測試應用來說會比較方便
using?static?System.Console; WriteLine("Hello?world");More
除了上面這些新特性,你覺得還有哪些比較實用的新特性呢,歡迎留言一起討論哈~
References
https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9
https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7
https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp9Sample/CleanCodeSample.cs
總結
以上是生活随笔為你收集整理的使用现代化 C# 语法简化代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 墙裂推荐:这可能是CAP理论的最好解释
- 下一篇: 创建支持依赖注入、Serilog 日志和