国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

微軟CONNECT(); 2016C#7.0新特性

2019-11-11 01:05:20
字體:
來源:轉載
供稿:網友

CONNECT(); 2016第 31 卷,第 12 期

.NET Framework - C# 7.0 中的新增功能

作者 Mark Michaelis | Connect(); 2016 | 獲取代碼早在 2015 年 12 月,我就談論過 C# 7.0 的設計 (msdn.com/magazine/mt595758)。在過去的一年里發生了很多變化,但是該團隊現在正致力于 C# 7.0 的開發,預期 Visual Studio 2017 候選發布版本將實現幾乎所有的新功能。(我之所以說是幾乎所有,是因為在 Visual Studio 2017 實際交付之前,仍可能會有進一步的變化。) 如需簡要概述,可以查看 itl.tc/CSharp7FeatureSummary 上的匯總表。在本文中,我將逐一詳細介紹這些新功能。

解構函數

從 C# 1.0 開始,就能調用函數,就是將參數組合起來并封裝到一個類中的構造函數。但是,從來沒有一種簡便的方式可將對象解構回其各個組成部分。例如,假設有一個 PathInfo 類,它采用文件名的每個元素(目錄名、文件名、擴展名),并將它們組合成一個對象,然后支持操作對象的不同元素。現在,假設你需要將該對象提取(解構)回其各個組成部分。在 C# 7.0 中,通過解構函數完成這項任務將變得輕而易舉,解構函數可返回對象的具體確定組件。注意,不要將解構函數 (deconstructor) 與析構函數 (destructor)(確定性對象解除分配和清除)或終結器 (itl.tc/CSharpFinalizers) 混淆。我們來看看圖 1 中的 PathInfo 類。圖 1 具有解構函數的 PathInfo 類及相關測試
public class PathInfo{  public string DirectoryName { get; }  public string FileName { get; }  public string Extension { get; }  public string Path  {    get    {      return System.IO.Path.Combine(        DirectoryName, FileName, Extension);    }  }  public PathInfo(string path)  {    DirectoryName = System.IO.Path.GetDirectoryName(path);    FileName = System.IO.Path.GetFileNameWithoutExtension(path);    Extension = System.IO.Path.GetExtension(path);  }  public void Deconstruct(    out string directoryName, out string fileName, out string extension)  {    directoryName = DirectoryName;    fileName = FileName;    extension = Extension;  }  // ...}顯然,可以和在 C# 1.0 一樣調用 Deconstruct 方法。但是,C# 7.0 提供了可以顯著簡化調用的語法糖。如果存在解構函數的聲明,則可以使用新的 C# 7.0“類似元組”的語法調用它(參見圖 2)。圖 2 解構函數調用和賦值
PathInfo pathInfo = new PathInfo(@"//test/unc/path/to/something.ext");{  // Example 1: Deconstructing declaration and assignment.  (string directoryName, string fileName, string extension) = pathInfo;  VerifyExpectedValue(directoryName, fileName, extension);}{  string directoryName, fileName, extension = null;  // Example 2: Deconstructing assignment.  (directoryName, fileName, extension) = pathInfo;  VerifyExpectedValue(directoryName, fileName, extension);}{  // Example 3: Deconstructing declaration and assignment with var.  var (directoryName, fileName, extension) = pathInfo;  VerifyExpectedValue(directoryName, fileName, extension);}請注意,C# 第一次如何允許同時向不同值的多個變量賦值。這與將所有變量都初始化為同一值 (null) 的空賦值聲明不同:
string directoryName, filename, extension = null;通過新的類似元組的語法,賦予每個變量一個不同的值,該值與其名稱不對應,但與它出現在聲明和解構語句中的順序相對應。正如你所期望的,out 參數的類型必須與被分配的變量類型相匹配,并且允許使用 var,因為此類型可以從 Deconstruct 參數類型中推斷出來。但是,請注意,雖然可以在圓括號外面放置一個 var(如圖 2 中的示例 3 所示),但此時即使所有變量的類型均相同,也不能拉出字符串。請注意,此時 C# 7.0 類似元組的語法要求圓括號內至少出現兩個變量。例如,即使存在類似如下的解構函數,也不允許使用 (FileInfo path) = pathInfo;:
public void Deconstruct(out FileInfo file)換句話說,不能對僅有一個 out 參數的 Deconstruct 方法使用 C# 7.0 解構函數。

使用元組

正如我所說過的,前面的每個示例都利用了 C# 7.0 類似元組的語法。此類語法的特點就是用圓括號括住分配的多個變量(或屬性)。我之所以使用術語“類似元組的”,是因為所有這些解構函數示例實際上在內部均未使用任何元組類型。(實際上,由于已分配的對象是表示封裝的組成部分的實例,因此,不允許通過解構函數語法分配元組,也可以說這樣做不太必要。)借助 C# 7.0,現在有了一種特別簡化的語法,可以使用元組,如圖 3 所示。只要允許使用類型說明符,就可以使用這種語法,其中包括聲明、強制轉換運算符和類型參數。圖 3 聲明、實例化并使用 C# 7.0 元組語法
[TestMethod]public void Constructor_CreateTuple(){  (string DirectoryName, string FileName, string Extension) pathData =    (DirectoryName: @"//test/unc/path/to",    FileName: "something",    Extension: ".ext");  Assert.AreEqual<string>(    @"//test/unc/path/to", pathData.DirectoryName);  Assert.AreEqual<string>(    "something", pathData.FileName);  Assert.AreEqual<string>(    ".ext", pathData.Extension);  Assert.AreEqual<(string DirectoryName, string FileName, string Extension)>(    (DirectoryName: @"//test/unc/path/to",      FileName: "something", Extension: ".ext"),    (pathData));  Assert.AreEqual<(string DirectoryName, string FileName, string Extension)>(    (@"//test/unc/path/to", "something", ".ext"),    (pathData));  Assert.AreEqual<(string, string, string)>(    (@"//test/unc/path/to", "something", ".ext"), (pathData));  Assert.AreEqual<Type>(    typeof(ValueTuple<string, string, string>), pathData.GetType());}[TestMethod]public void ValueTuple_GivenNamedTuple_ItemXHasSameValuesAsNames(){  var normalizedPath =    (DirectoryName: @"//test/unc/path/to", FileName: "something",    Extension: ".ext");  Assert.AreEqual<string>(normalizedPath.Item1, normalizedPath.DirectoryName);  Assert.AreEqual<string>(normalizedPath.Item2, normalizedPath.FileName);  Assert.AreEqual<string>(normalizedPath.Item3, normalizedPath.Extension);}static public (string DirectoryName, string FileName, string Extension)  SplitPath(string path){  // See http://bit.ly/2dmJIMm Normalize method for full implementation.  return (              System.IO.Path.GetDirectoryName(path),    System.IO.Path.GetFileNameWithoutExtension(path),    System.IO.Path.GetExtension(path)    );}如果你不太熟悉元組,可以在輕量級語法中將多個類型組合成一個包含類型,然后在對其進行實例化的方法外面使用。之所以說是輕量級,是因為和定義類/結構不同,元組可通過內聯和動態方式“聲明”。但是,與也支持內聯聲明和實例化的動態類型不同,元組可以從其包含成員的外部訪問,它們實際上可以包含在 API 中。雖然外部 API 支持,但元組沒有兼容版本的擴展(除非類型參數本身正好支持推導),因此,在公共 API 中應謹慎使用。因此,更好的辦法是對公共 API 中的返回內容使用標準類。在 C# 7.0 之前,該框架已有元組類 System.Tuple<…>(在 Microsoft .NET Framework 4 中引入)。但 C# 7.0 與之前的解決方案不同,因為它將語義意圖嵌入到聲明中并引入一個元組值類型:  System.ValueTuple<…>。我們現在來看看語義意圖。請注意,在圖 3 中,C# 7.0 元組語法可讓你為元組包含的每個 ItemX 元素聲明別名。例如,圖 3 中的 pathData 元組實例已定義強類型 DirectoryName: string、FileName: string 和 Extension: string 屬性,因此,可以調用(例如)pathData.DirectoryName。這是一項重大改進,因為在 C# 7.0 之前,唯一可用的名稱是 ItemX 名稱,其中 X 將針對每個元素增加。現在,雖然 C# 7.0 元組的元素屬于強類型,但這些名稱本身在類型定義中并未區分。因此,可以分配兩個使用不同別名的元組,你將得到一條警告,通知你將忽略右邊的名稱:
// Warning: The tuple element name 'AltDirectoryName1' is ignored// because a different name is specified by the target type...(string DirectoryName, string FileName, string Extension) pathData =  (AltDirectoryName1: @"//test/unc/path/to",  FileName: "something", Extension: ".ext");同樣,可以將元組分配到尚未定義部分別名元素名稱的其他元組:
// Warning: The tuple element name 'directoryName', 'FileNAme' and 'Extension'// are ignored because a different name is specified by the target type...(string, string, string) pathData =  (DirectoryName: @"//test/unc/path/to", FileName: "something", Extension: ".ext");必須確定,每個元素的類型和順序都定義類型兼容性。僅忽略元素名稱。然而,即使在名稱不同時被忽略,它們仍然在 IDE 中提供 IntelliSense。請注意,無論是否定義元素名稱的別名,所有元組均有 ItemX 名稱,其中 X 對應于元素的數量。ItemX 名稱很重要,因為它們是元組從 C# 6.0 開始起可用,即使沒有別名元素的名稱也是如此。需要注意的另一點就是,基礎 C# 7.0 元組類型是 System.ValueTuple。如果正針對其進行編譯的框架中未提供此類型,可以通過 NuGet 包訪問它。有關元組內部元素的詳細信息,請參閱 intellitect.com/csharp7tupleiinternals。

具有 Is 表達式的模式匹配

有時會存在基類(例如 Storage),以及一系列的派生類、DVD、UsbKey、HardDrive、FloppyDrive 等。要對每個類實施 Eject 方法,請使用以下多個選項:As 運算符使用 As 運算符轉換并賦值檢查結果是否為 null執行 eject 操作Is 運算符使用 Is 運算符檢查類型轉換類型并為其賦值執行 eject 操作Cast顯式轉換并賦值捕獲可能的異常執行操作看起來不怎么樣啊!還有第四種、效果更好的方法,即使用你通過虛擬函數分派的多形性。但是,僅在具有 Storage 類的源代碼并且可以添加 Eject 方法時,才可以使用這種方法。我假設的選項不適用于這個討論,因此需要模式匹配。上述這些方法存在的問題都是語法相當冗長,總是要求為需要轉換的每個類提供多個語句。C# 7.0 提供模式匹配,用作一種將測試和賦值合并為單個操作的方法。因此,圖 4 中的代碼簡化為如圖 5 中所示的代碼。圖 4 無模式匹配的類型轉換
// Eject without pattern matching.public void Eject(Storage storage){  if (storage == null)  {    throw new ArgumentNullException();  }  if (storage is UsbKey)  {    UsbKey usbKey = (UsbKey)storage;    if (usbKey.IsPluggedIn)    {      usbKey.Unload();      Console.WriteLine("USB Drive Unloaded.");    }    else throw new NotImplementedException();    }  else if(storage is DVD)  // ...  else throw new NotImplementedException();}圖 5 有模式匹配的類型轉換
// Eject with pattern matching.public void Eject(Storage storage){  if (storage is null)  {    throw new ArgumentNullException();  }  if ((storage is UsbKey usbDrive) && usbDrive.IsPluggedIn)  {    usbDrive.Unload();    Console.WriteLine("USB Drive Unloaded.");  }  else if (storage is DVD dvd && dvd.IsInserted)  // ...  else throw new NotImplementedException();  // Default}這兩種轉換方式的區別并不重要,但如果要經常執行(例如,針對每個派生類型),則前一種語法存在一種繁瑣的 C# 特性。C# 7.0 的改進之處是將類型測試、聲明和賦值組合為一個操作,呈現早期的語法,但不推薦使用。在前一種語法中,檢查類型而不分配標識符會導致失敗而恢復“默認設置”,否則會很麻煩。相比之下,除了類型檢查,分配還考慮到其他條件。請注意,圖 5 中的代碼開始模式匹配 is 運算符,也支持 null 比較運算符:
if (storage is null) { ... }

使用 Switch 語句的模式匹配

雖然支持使用 is 運算符的模式匹配實現了改進,但 switch 語句的模式匹配支持無疑更重要,至少在有多個可轉換的兼容類型時如此。這是因為 C# 7.0 包括 case 語句和模式匹配,此外,如果滿足 case 語句中的類型模式,就可以在 case 語句中提供、分配和訪問標識符。圖 6 提供了一個示例。圖 6 Switch 語句中的模式匹配
public void Eject(Storage storage){  switch(storage)  {    case UsbKey usbKey when usbKey.IsPluggedIn:      usbKey.Unload();      Console.WriteLine("USB Drive Unloaded.");      break;    case DVD dvd when dvd.IsInserted:      dvd.Eject();      break;    case HardDrive hardDrive:      throw new InvalidOperationException();    case null:    default:      throw new ArgumentNullException();  }}在該示例中,請注意如何在 case 語句中自動聲明和分配如 usbKey 和 dvd 的局部變量。正如你所期望的,范圍僅限于 case 語句中。但也許與變量聲明和賦值一樣重要的是附加條件,可以用一個 when 子句附加到 case 語句。結果是 case 語句完全可以篩選無效的方案,無需在 case 語句內部使用額外的篩選器。這帶來額外的好處是:如果事實上沒有完全滿足前一個 case 語句,也允許計算下一個 case 語句。這也意味著 case 語句不再僅限于常量,此外,switch 表達式可以是任何類型,不再僅限于 bool、char、string、integral 和 enum。新的 C# 7.0 模式匹配 switch 語句功能引入的另一個重要特征就是,case 語句順序很重要并在編譯時驗證。(這與該語言的早期版本形成對比,早期版本中沒有模式匹配,case 語句順序也不重要。) 例如,如果我在派生自 Storage 的模式匹配 case 語句之前引入了 Storage 的 case 語句(UsbKey、DVD 和 HardDrive),則 case Storage 會隱藏所有其他的類型模式匹配(派生自 Storage)。如果 case 語句來自隱藏計算結果中的其他派生類型 case 語句的基類,將導致隱藏的 case 語句中出現編譯錯誤。這樣,case 語句順序要求就類似于 catch 語句。讀者將會記得 null 值中的 is 運算符返回 false。因此,對于值 null 的 switch 表達式,類型模式匹配 case 語句不匹配。為此,null case 語句的順序無關緊要;此行為在模式匹配之前與 switch 語句匹配。此外,為了支持與 C# 7.0 之前的 switch 語句的兼容性,默認總是最后評估 case,而不考慮它出現在 case 語句順序中的位置。(也就是說,由于 case 總是在最后評估,可讀性通常也會將它放在最后。) 此外,goto case 語句仍僅適用于常量 case 標簽,不適用于模式匹配。

本地函數

雖然已經可以聲明委托并為其分配一個表達式,但是 C# 7.0 通過允許在另一個成員內部完全聲明本地函數,做出了進一步改進。請考慮圖 7 中的 IsPalindrome 函數。圖 7 本地函數示例
bool IsPalindrome(string text){  if (string.IsNullOrWhiteSpace(text)) return false;  bool LocalIsPalindrome(string target)  {    target = target.Trim();  // Start by removing any surrounding whitespace.    if (target.Length <= 1) return true;    else    {      return char.ToLower(target[0]) ==        char.ToLower(target[target.Length - 1]) &&        LocalIsPalindrome(          target.Substring(1, target.Length - 2));    }  }  return LocalIsPalindrome(text);}在該實現中,我先檢查傳遞到 IsPalindrome 的參數不是 null 或僅為空格。(我已使用模式匹配與 “text is null” 進行 null 檢查。) 接下來,我聲明函數 LocalIsPalindrome,其中,我以遞歸方式將第一個和最后一個字符進行比較。這種方法的好處是,我不在可能會錯誤調用的類范圍內聲明 LocalIsPalindrome,進而繞過 IsNullOrWhiteSpace 檢查。換句話說,本地函數提供其他的范圍限制,但僅在周圍函數內部。圖 7 中的參數驗證方案是一種通用的本地函數用例。我經常遇到的另一個方案發生在單元測試內,例如在測試 IsPalindrome 函數時(參見圖 8)。圖 8 單元測試通常使用本地函數
[TestMethod]public void IsPalindrome_GivenPalindrome_ReturnsTrue(){  void AssertIsPalindrome(string text)  {    Assert.IsTrue(IsPalindrome(text),      $"'{text}' was not a Palindrome.");  }  AssertIsPalindrome("7");  AssertIsPalindrome("4X4");  AssertIsPalindrome("   tnt");  AssertIsPalindrome("Was it a car or a cat I saw");  AssertIsPalindrome("Never odd or even");}返回 IEnumerable<T> 的 Iterator 函數以及 yield 返回元素是另一種通用的本地函數用例。作為對該主題的總結,以下列出了大家需要注意的有關本地函數的幾個要點:本地函數不允許使用可訪問性修飾符(public、PRivate、protected)。本地函數不支持重載。即使簽名未重疊,也不能在名稱相同的同一種方法中使用兩個本地函數。編譯器將針對永不調用的本地函數發出警告。本地函數可以訪問封閉范圍內的所有變量,包括局部變量。此行為與本地定義的 lambda 表達式相同,除了本地函數不分配表示結束的對象外,其他方面都與本地定義的 lambda 表達式相同。本地函數存在于整個方法的范圍內,而不考慮是在聲明之前還是之后調用它們。

通過引用返回

從 C# 1.0 開始,可以通過引用 (ref) 將參數傳遞給函數。結果就是對參數本身的任何改變都將傳回給調用方。請考慮以下 Swap 功能:
static void Swap(ref string x, ref string y)在這種情況下,被調用方法可以用新值更新原始調用方的變量,從而交換第一和第二參數中存儲的內容。從 C# 7.0 開始,除了 ref 參數,還可以通過函數返回傳回一個引用。例如,考慮返回圖像中與紅眼相關聯的第一像素的函數,如圖 9 所示。圖 9 Ref 返回和 Ref 局部聲明
public ref byte FindFirstRedEyePixel(byte[] image){  //// Do fancy image detection perhaps with machine learning.  for (int counter = 0; counter < image.Length; counter++)  {    if(image[counter] == (byte)ConsoleColor.Red)    {      return ref image[counter];    }  }  throw new InvalidOperationException("No pixels are red.");}[TestMethod]public void FindFirstRedEyePixel_GivenRedPixels_ReturnFirst(){  byte[] image;  // Load image.  // ...    // Obtain a reference to the first red pixel.  ref byte redPixel = ref FindFirstRedEyePixel(image);  // Update it to be Black.  redPixel = (byte)ConsoleColor.Black;  Assert.AreEqual<byte>((byte)ConsoleColor.Black, image[redItems[0]]);}通過返回圖像引用,調用方然后能夠將像素更新為不同的顏色。通過數組檢查更新時發現,該值現在為 black。使用 by reference 參數的替代方法如下所示,有人可能會說這種方法不太明顯、可讀性較低:
public bool FindFirstRedEyePixel(ref byte pixel);通過引用返回有兩個重要的限制,并且這兩個限制都由對象生命周期造成。對象引用不應被視為垃圾收集,因為對象仍然被引用,當它們不再有任何引用時,不應消耗內存。首先,只能返回以下內容的引用:字段、其他引用返回屬性或函數,或作為參數傳遞到引用返回函數的對象。例如,FindFirst-RedEyePixel 返回對圖像數組中項目的引用,它是函數的參數。同樣,如果圖像存儲為類中的字段,則可以通過引用返回該字段:
byte[] _Image;public ref byte[] Image { get {  return ref _Image; } }其次,ref 局部變量初始化為內存中的某個存儲位置,且不能修改為指向不同的位置。(不能具有指向一個引用的指針和修改引用 - 對于那些有 C++ 背景的人,是指向指針的指針。)以下是需要了解的幾個按引用返回特征: 如果你要返回一個引用,則顯然必須返回。因此,這意味著在圖 9 的示例中,即使沒有紅眼像素存在,仍需要返回 ref 字節。唯一的解決方法是引發一個異常。相比之下,by reference 參數方法可讓你保持參數不變,并返回一個指示成功的布爾值。在許多情況下,這種方法可能更可取。聲明一個引用局部變量時,需要初始化。這涉及到為它分配從函數或引用返回到變量的 ref:
ref string text;  // Error雖然可以在 C# 7.0 中聲明引用局部變量,但不允許聲明 ref 類型的字段:
class Thing { ref string _Text;  /* Error */ }不能為自動實施的屬性聲明 by reference 類型:
class Thing { ref string Text { get;set; }  /* Error */ }允許使用返回引用的屬性:
class Thing { string _Text = "Inigo Montoya";   ref string Text { get { return ref _Text; } } }不能使用值(如 null 或常量)初始化引用局部變量。它必須通過返回成員或局部變量/字段的 by reference 分配: 
ref int number = null; ref int number = 42;  // ERROR

輸出變量

從 C# 的第一個版本開始,調用包含輸出參數的方法時,始終要求在調用方法之前預先聲明輸出參數標識符。但 C# 7.0 刪除了這個特性,并且允許以內聯方式聲明輸出參數以及方法調用。圖 10 顯示了一個例子。圖 10 輸出參數的內聯聲明
public long DivideWithRemainder(  long numerator, long denominator, out long remainder){  remainder = numerator % denominator;  return (numerator / denominator);}[TestMethod]public void DivideTest(){  Assert.AreEqual<long>(21,    DivideWithRemainder(42, 2, out long remainder));  Assert.AreEqual<long>(0, remainder);}請注意,在 DivideTest 方法中,從測試中對 DivideWithRemainder 的調用如何在 out 修飾符之后包含一個類型說明符。此外,了解剩余部分如何自動繼續包含在方法的范圍內,如第二個 Assert.AreEqual 調用證明。很好!

文本改進

與以前的版本不同,C# 7.0 包含數字二進制文本格式,如下例所示:
long LargestSquareNumberUsingAllDigits =  0b0010_0100_1000_1111_0110_1101_1100_0010_0100;  // 9,814,072,356long MaxInt64 { get; } =  9_223_372_036_854_775_807;  // Equivalent to long.MaxValue還要注意對下劃線 “_” 用作數字分隔符的支持。它只是用來提高可讀性,可以放在數字位數(二進制、十進制或十六進制數字)之間的任何位置。

通用的異步返回類型

有時在實施異步方法時,能夠同步返回結果,縮短一個長時間運行的操作,因為結果幾乎是瞬時的,甚至是已知的。例如,考慮一個異步方法,用于確定目錄 (bit.ly/2dExeDG) 中文件的總大小。事實上,如果該目錄中沒有文件,則該方法可以立即返回,而不執行長時間運行的操作。直到 C# 7.0,異步語法的要求規定此類方法的返回結果應當是 Task<long>,因此,即使不需要這樣的 Task 實例,也要實例化 Task。(要實現這一點,通用模式是從 Task.FromResult<T> 返回結果。)在 C# 7.0 中,編譯器不再限制異步方法返回到 void、Task 或 Task<T>。現在可以定義自定義類型,例如 .NET Core Framework 提供的 System.Threading.Tasks.ValueTask<T> struct,它們與異步方法返回值兼容。有關更多信息,請參閱 itl.tc/GeneralizedAsyncReturnTypes。

更多的 Expression-Bodied 成員

C# 6.0 引入了函數和屬性的 expression-bodied 成員,從而簡化了實現瑣碎的方法和屬性的語法。在 C# 7.0 中,將 expression-bodied 實現添加到了構造函數、訪問器(get 和 set 屬性實現),甚至終結器中(請參見圖 11)。圖 11 在訪問器和構造函數中使用 Expression-Bodied 成員
class TemporaryFile  // Full IDisposible implementation                     // left off for elucidation.{  public TemporaryFile(string fileName) =>    File = new FileInfo(fileName);  ~TemporaryFile() => Dispose();  Fileinfo _File;  public FileInfo File  {    get => _File;    private set => _File = value;  }  void Dispose() => File?.Delete();}我希望使用 expression-bodied 成員,這對于終結器特別常見,因為最常見的實現是調用 Dispose 方法,如上圖所示。我很高興地在此說明,對 expression-bodied 成員的額外支持是由 C# 社區實施的,而不是 Microsoft C# 團隊。而且還是開源,耶!警告: 此功能在 Visual Studio 2017 RC 中尚未實現。

Throw 表達式:

圖 11 中的臨時類可以得到增強,在 expression-bodied 成員內包括參數驗證;因此,我可以將構造函數更新為:
public TemporaryFile(string fileName) =>  File = new FileInfo(filename ?? throw new ArgumentNullException());如果沒有 throw 表達式,C# 對 expression-bodied 成員的支持就不能進行任何參數驗證。但是,通過 C# 7.0 支持 throw 作為一個表達式,而不僅僅是一個語句,因此,可以在更大的包含表達式中報告錯誤內聯。警告: 此功能在 Visual Studio 2017 RC 中尚未實現。

總結

我承認,當我開始寫這篇文章,以為它會短得多。然而,由于我花了更多的時間編程和測試這些功能,因此,我發現有更多的方式實現 C# 7.0,而不僅僅是通過閱讀功能標題和遵照語言開發。在許多情況下,聲明變量、二進制文本、throw表達式等等,沒有太多地涉及理解和使用功能。但有幾種情況(例如,按引用返回、解構函數和元組)需要比最初所預期的更多地了解功能。在后一種情況下,不僅要了解語法,還要知道功能何時是相關的。C# 7.0 繼續在快速減少的特性列表(預先聲明的輸出標識符和缺少 throw 表達式)中削弱,而與此同時進行擴展,以包括對之前在語言級別看不到的功能的支持(元組和模式匹配)。希望這個介紹可以幫助你快速進入 C# 7.0 編程領域。有關本文內容之后的 C# 7.0 開發的更多信息,請查看我在 intellitect.com/csharp7 上的博客,以及我的《Essential C# 7.0》一書的更新(預計將在 Visual Studio 2017 投入生產后不久面世)。
Mark Michaelis 是 IntelliTect 的創始人,擔任首席技術架構師和培訓師。在近二十年的時間里,他一直是 Microsoft MVP,并且自 2007 年以來一直擔任 Microsoft 區域總監。Michaelis 還是多個 Microsoft 軟件設計評審團隊(包括 C#、Microsoft Azure、SharePoint 和 Visual Studio ALM)的成員。他在開發者會議上發表了演講,并撰寫了大量書籍,包括最新的“必備 C# 6.0(第 5 版)”(itl.tc/EssentialCSharp)。可通過他的 Facebook facebook.com/Mark.Michaelis、博客IntelliTect.com/Mark、Twitter @markmichaelis 或電子郵件 mark@IntelliTect.com 與他取得聯系。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 林西县| 东乡县| 南宁市| 池州市| 平和县| 湖口县| 诸城市| 永和县| 遂昌县| 新泰市| 蒙自县| 永昌县| 南江县| 白朗县| 衢州市| 大余县| 隆德县| 娄底市| 偏关县| 浪卡子县| 韶山市| 托克逊县| 恩施市| 商南县| 皮山县| 凌源市| 葫芦岛市| 衡阳市| 砀山县| 神农架林区| 宜宾县| 岳阳市| 政和县| 晋中市| 阳东县| 雷州市| 望谟县| 寻甸| 阿克陶县| 嘉义县| 宾川县|