C# 6以前咱們構建只讀自動屬性:web
1 public string FirstName { get; private set; } 2 public string LastName { get; private set; }
原理解析:就是編譯器在生成set訪問器時,它的修飾符是private,由上可知所謂的只讀只是針對類外部,在類內部仍是能夠隨意修改屬性值的。express
C# 6中提供了真正的只讀自動屬性,寫法以下:編程
1 public string FirstName { get; } 2 public string LastName { get; }
原理解析:首先編譯器會生成一個readonly的私有字段而get訪問器就是返回該字段的值,由上可知該只讀自動屬性只能在構造函數中爲其賦值。異步
之前自動屬性的賦值操做咱們只能寫在方法中,如構造函數:async
1 public Student(string firstName, string lastName) 2 { 3 FirstName = firstName; 4 LastName = lastName; 5 }
但在C# 6中咱們能夠把賦值操做看成聲明的一部份,以下所示:異步編程
1 public string FirstName { get; set; } = "Corleone"; 2 public string LastName { get; set; } = "Mike";
備註:其實C# 6和以前的版本都同樣賦值操做最終都是在方法中完成,但後者明顯更簡潔直觀,因此這是個不錯的語法糖。函數
C# 6中提供的一個新語法:對於只有一條語句的方法體能夠簡寫成表達式。以下面兩種狀況:spa
1. 方法(Methods).net
1 public Student Create() => new Student();
等同於:設計
1 public Student Create() 2 { 3 return new Student(); 4 }
2. 只讀屬性(read only properties)
1 public string FullName => string.Format("{0},{1}", FirstName, LastName);
等同於:
1 public string FullName 2 { 3 get 4 { 5 return string.Format("{0},{1}", FirstName, LastName); 6 } 7 }
原理解析:上面的表達式在編譯後會生成最原始的方法體和訪問器,值得一提的是函數表達式體跟Lambda是兩個類似但不相同的東西,函數的表
達式體只能帶一句話且不能包含return關鍵字但Lambda 能帶語句塊和包含關鍵字。
C# 6中的一個新語法:使用類型的靜態成員時能夠省略其類型,以下所示:
1 using static System.String; // 先導入對應成員類型 2 public bool IsNull(string str) => IsNullOrEmpty(str);
等同於:
1 public bool IsNull(string str) => string.IsNullOrEmpty(str);
總結:該語法糖的目的是使代碼變得更簡潔,但這個應該是區分使用場景的,如:數學計算(Math類)使用此語法糖的確可以簡潔代碼提升可讀
性,但在某處若是導入過多的類型那麼不只不能提升閱讀性反而會增長閱讀難度,由於你不知道這些成員具體屬於那個類型。還有若類型自己存在
同名成員使用時則會使用類型成員覆蓋。
注意:使用靜態這一語法糖並不適用擴展方法,由於擴展方法的設計理念就是不修改已有代碼且只能在必定範圍內使用,因此在特殊狀況下須要將
其看成靜態方法來使用,那麼使用類名調用反而是比較明智的。
稍有經驗的童鞋都知道在Coding過程當中常常要判斷變量的值是否爲null,相似這種if-else的操做還很多。這使得代碼看起來十分不簡潔,好在C#6
中提供瞭解決方法:
1 var student = new Student(); 2 var firstName = student?.FirstName;
等同於:
1 var student = new Student(); 2 3 string firstName = null; 4 if (student != null) 5 { 6 firstName = student.FirstName; 7 }
使用方法:只需替換成員訪問符 . 爲 ?. ,若 ?. 左邊爲null則整個運算符的結果也爲null,不然運算符的結果就等於其成員值。假如成員的類型爲值
類型則整個表達式返回的類型是對應類型的可空類型,如:
1 int? age = student?.Age;
原理解析: ?. 編譯後就是 if 或 三元運算符,非賦值操做(如:call)會編譯成 if,賦值操做通常會編譯成三元運算符。
C# 6中提供了一種新語法來構建格式化字符串,如:
1 var fullName = $"{student.FirstName},{student.LastName}";
等同於:
1 var fullName = string.Format("{0},{1}", student.FirstName, student.LastName);
使用方法:只需在字符串前加上$符號,而後在大括號中填寫表達式(字段、方法、Lambdad...)便可。
備註:
1. 字符串插值語法支持之前全部字符串格式設置(此項僅支持 .net framework,不支持 .net core 1.0.1),如:
1 Console.WriteLine($"平均成績:{student.GPA:F2}");
注:由於 : 總被編譯器解釋爲表達式與字符串格式的分隔符,因此表達式中如有條件運算符則咱們須要用括號來強制編譯將其解析成當前語境所要
表達的意義。如:
1 Console.WriteLine($"平均成績:{(student.GPA > 80 ? student.GPA : 0):F2}");
2. 字符串插值語法能夠嵌套,如:
1 var score = $"個人各科成績:{ $"數學:{student.MathScores};英語:{student.EnglishScore};"}";
原理解析:$"xxx{expression1}xxx{expression2}..." 編譯後就是string.Format()。
C# 6中的一個新功能就是異常過濾器,它可使咱們在恰當的時機來應用Catch子句,如:
1 try 2 { 3 throw new WebException("Request timed out..", WebExceptionStatus.Timeout); 4 } 5 catch (WebException webEx) when (webEx.Status == WebExceptionStatus.Timeout) 6 { 7 // Exception handling 8 }
使用方法:try-catch() when()。
總結:異常過濾器最大的亮點就是在使用恰當的狀況下能夠不丟失異常引起點的堆棧信息,這對程序的排錯相當重要。另外它還有不少有意思的用
法,你們能夠上網查下。
nameof 表達式的功能是獲取成員名稱,如拋異常:
1 public string FullName(Student student) 2 { 3 if (student == null) 4 throw new ArgumentNullException(nameof(student)); 5 6 return $"{student.FirstName},{student.LastName}"; 7 }
優勢:nameof 表達式它可以理解成員,當成員被重命名時nameof表達式中也重命名了,而常量字符串表示法是沒有這樣的優點。
缺點:nameof 表達式生成的是不徹底限定名,若你須要徹底限定名 nameof 就不能幫你了。
原理解析:nameof 是編譯期間就肯定其(成員)字符串名稱的,即編譯後就是常量字符串的表現形式了。
C# 5 提供的 async 和 await 使異步編程變得極爲簡便,但它們也有着侷限性:await在catch和finally塊中不能使用。但這個問題已在C# 6中獲得
瞭解決,如:
1 public static async Task<string> MakeRequestAndLogFailures() 2 { 3 await logMethodEntrance(); 4 try 5 { 6 // .... 7 var responseText = await streamTask; 8 return responseText; 9 } 10 catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301")) 11 { 12 await logError("Recovered from redirect", e); 13 return "Site Moved"; 14 } 15 finally 16 { 17 await logMethodExit();
18 } 19 }
這個功能並無什麼新意,其實之前就支持集合/字典 初始化器了,如:
1 var list = new List<string>() 2 { 3 "Mike", 4 "Jim" 5 }; 6 7 var dic = new Dictionary<int, string>() 8 { 9 { 20, "Mike" }, 10 { 30, "Jim" } 11 };
在C# 6中只是字典初始化器支持了新的寫法,如:
1 var dic = new Dictionary<int, string>() 2 { 3 [20] = "Mike", 4 [30] = "Jim" 5 };
總結:暫無發現特殊的用法。
這算不上是新語法,由於僅僅是編譯器的改進,之因此一提是想讓你們知道有這麼一回事。之前的編譯器是識別不了 Task.Run(Func<Task>())
的,以下:
1 static Task DoThings() 2 { 3 return Task.FromResult(0); 4 } 5 6 Task.Run(DoThings); // 此處省略方法代碼...
上述代碼在老版本編譯器下是編譯不經過的,而在新版本編譯器是能編譯經過的。
備註:值得一提的是新版本編譯器也只是識別了Task.Run(Func<Task>()),Task.Run(Action) 仍是識別不了,總的來講此功能對咱們用處不大,
還不如乖乖的寫回Lambda表達式。
因爲篇幅所限,C# 7 新增的功能就放在下篇介紹......