[譯]C# 7系列,Part 1: Value Tuples

来源:https://www.cnblogs.com/wenhx/archive/2019/12/01/c-7-series-part-1-value-tuples.html

Mark Zhou寫了很不錯的一系列介紹C# 7的文章,雖然是2年多年前發佈的,不過對於不熟悉C# 7特性的同學來說,仍然有很高的閱讀價值。 原文:https://blogs.msdn.microsoft.com/mazhou/2017/05/26/c-7-series-part-1-value-t ...


Mark Zhou寫了很不錯的一系列介紹C# 7的文章,雖然是2年多年前發佈的,不過對於不熟悉C# 7特性的同學來說,仍然有很高的閱讀價值。

原文:https://blogs.msdn.microsoft.com/mazhou/2017/05/26/c-7-series-part-1-value-tuples/

 

譯文:

從今天開始,我將開始一個新的C# 7系列文章,介紹C# 7+的新語言特性。請註意,我說的不是C# 7.0,我說的是C# 7+,因為將會有一些小的版本(比如7.1、7.2)逐步引入新的特性(感謝Roslyn!),比如async Main和default literals。

Tuples

類System.Tuple提供了一種類型來表示類似屬性包的鍵值對。當你想用一種數據結構來保存一個帶有屬性(元素)的對象,但又不想創建一個單獨的類型的時候,你可以使用它。下麵的代碼展示瞭如何用它作為一個方法的返回值,這個返回值包含了學生姓名和年齡。

public Tuple<string, int> GetStudentInfo(string id)
{     
    // Search by ID and find the student.
    return new Tuple<string, int>("Annie", 25);
}

可以看到,我返回了一個Tuple<string,int>的實例對象,它的第一個參數是name,第二個參數是age。之後,我們在代碼中調用這個方法,像這樣:

public void Test()
{     
    Tuple<string, int> info = GetStudentInfo("100-000-1000");
    Console.WriteLine($"Name: {info.Item1}, Age: {info.Item2}");
}

你可以通過引用Item1和Item2來訪問name和age。

Tuple類有一些明顯的問題:

  • 您需要使用ItemX這樣的形式來訪問屬性,這樣的屬性名可能對調用者來說沒有什麼含義,如果我們可以使用類似info.Nameinfo.Age這樣的形式來訪問會比info.Item1info.Item2更好
  • 最多只能有8個屬性。如果需要更多,最後一個類型參數必須是另一個元組。這使得語法非常難以理解。
  • Tuple是一種引用類型,不像其他基本類型(它們是大多數值類型),它分配在堆上,對於CPU密集型操作來說,它可能需要太多的對象創建/分配。

Value Tuples

C# 7.0引入了ValueTuple結構,它是Tuple對象的值類型表示。C#語言團隊為這個值元組類型做了很多不錯的事情,包括新的語法和許多特性(比如解構)。

下麵是使用Value Tuples的重寫版本,請註意,如果在你的項目中不能用ValueTuple類型,那你必須通過NuGet下載System.ValueTuple 4.3.0 NuGet包到你的項目。如果您使用的是.Net Framework 4.7或更高版本,或者.Net Standard Library 2.0或更高版本,你什麼也不用做,ValueTuple已經包含在內了。

public (string, int) GetStudentInfo(string id)
{
    // Search by ID and find the student. 
    return ("Annie", 25);
}
 
public void Test()
{ 
    (string, int) info = GetStudentInfo("100-000-1000"); 
    Console.WriteLine($"Name: {info.Item1}, Age: {info.Item2}");
}

通過使用語法(),上面的代碼得到了極大的簡化。 
您甚至可以為ValueTuple中的每個元素指定一個名稱,如下所示:

public (string name, int age) GetStudentInfo(string id)
{
    // Search by ID and find the student.
    return (name: "Annie", age: 25);
}
 
public void Test()
{
    (string name, int age) info = GetStudentInfo("100-000-1000"); 
    Console.WriteLine($"Name: {info.name}, Age: {info.age}");
}

帥!現在你的元組對象中的元素有了好的元數據,那麼你就不需要來回檢查確認返回/訪問元素的順序是正確的了。

當您使用值元組時,Visual Studio IDE會給您提示。

Value Tuple 解構

您可以從值元組對象中解構元素,並訪問局部變數。

// 解構使用 var (x, y) 語法,
// 或者 (var x, var y) 語法。
var (name, age) = GetStudentInfo("100-000-1000");
// 現在你有兩個局部變數:name and age.
Console.WriteLine($"Name: {name}, Age: {age}");

如果只關心某些元素而不是所有元素,可以使用_關鍵字忽略局部變數。

var (name, _) = GetStudentInfo("100-000-1000");
// 現在你只有一個局部變數:name,值age被忽略了。
Console.WriteLine($"Name: {name}");

從Value Tuples到Tuples

類型System.TupleSystem.ValueTuple提供了一些擴展方法來幫助它們之間相互轉換。

var valueTuple = (id: 1, name: "Annie", age: 25, dob: DateTime.Parse("1/1/1993"));
var tuple = valueTuple.ToTuple();

 

結論

ValueTuple使C#語言更現代,更易於使用簡化的語法。它解決了許多Tuple的問題:

  • 值元組對象具有第一類語法支持,它簡化了使用元組元素的代碼。
  • 您可以用一個名稱與值元組的元素相關聯,從而獲得一定程度的設計階段和編譯器階段的代碼驗證。
    請註意,與元組元素相關聯的名字不是一個運行時的元數據,即在運行時的實例值元組中不存在這樣一個名稱的屬性/欄位,屬性的名稱仍Item1、Item2等等,所有的元素名稱僅存在設計和編譯階段。
  • 你現在可以通過使用解構和_關鍵字靈活地訪問所有元組元素,或者其中的一部分。
  • 值元組類型是值類型,沒有繼承或其他特性,這意味著值元組具有更好的性能。

由於值元組元素的名稱不是運行時的,所以在使用一些類庫(如Newtonsoft)進行序列化時,必須小心使用元組類型。除非你更新過支持新元數據(TupleElementNameAttribute等)的類庫,否則你會遇到bug。


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

更多相關文章
  • [TOC] 1. 概述 本來是不想寫Paramiko的,因為我覺得之前的一篇關於Netmiko模塊更適合網工,後來發現paramiko有包含SFTP功能,所以還是有必要來講講,畢竟我們在設備上是要經常下載配置、上傳版本/升級版本用的,而且SFTP比FTP、TFTP更安全。 所以, 你也不用藉助其他工 ...
  • 01 實現自定義的可變長數組類型 假設我們要實現一個會自動擴展的數組,要實現什麼函數呢?先從下麵的main函數給出的實現,看看有什麼函數是需要我們實現的。 輸出結果: 要實現的方式,要做哪些事情呢?我先列一下: 要用動態分配的記憶體來存放數組元素,需要一個指針成員變數 重載賦值=運算符 重載[]運算符 ...
  • 01 賦值運算符重載的需求 有時候希望賦值運算符兩邊的類型可以不匹配,比如:把一個 int 類型變數賦值給一個Complex(複數)對象,或把一個 char 類型的字元串賦值給一個字元串對象,此時就需要重載賦值運算符‘=’。 需要註意的是:賦值運算符 只能重載為成員函數。 02 賦值運算符重載的例子 ...
  • 01 運算符重載的需求 C++ 預定義的運算符,只能用於基本數據類型的運算:整型、實型、字元型、邏輯型等等,且不能用於對象的運算。但是我們有時候又很需要在對象之間能用運算符,那麼這時我們就要 重載運算符 ,使得運算符能用於對象之間的運算。 比如,在數學上,兩個複數可以直接進行+、 等運算,但在C++ ...
  • 本系列將和大家分享下ASP.NET Core Web 應用程式的一些基礎知識,本章主要簡單介紹下在ASP.NET Core中如何使用AutoMapper進行實體映射。 ...
  • 作為開發人員,您始終需要處理應用程式配置數據。常見的示例是INI 文件,XML文件, .NET配置文件(也稱為“ .config”),Windows註冊表和命令行(argv)參數。配置文件的優點是它們載入速度快,不占用大量空間且易於編輯。Nini是一個功能強大的 .NET配置庫,旨在幫助快速構建高度... ...
  • 探究 C 中的 char 、 string(一) [TOC] 1. System.Char 字元 char 是 System.Char 的別名。 System.Char 占兩個位元組,16個二進位位。 System.Char 用來表示、存儲一個 Unicode 字元。 System.Char 的表示範 ...
  • 今天介紹一個開源的C# WPF開源控制項庫,非常漂亮,重點是開源哦 WPF做桌面開發是很有優勢的,除了微軟自帶的控制項外,還有很多第三方的控制項庫,比如收費的Dev Express For WPF、Telerik For WPF等,及Github上開源免費的控制項庫如MaterialDesignInXAML ...
一周排行
  • 本文將介紹如何在.NET Core3環境下使用MVVM框架Prism的使用事件聚合器實現模塊間的通信 一.事件聚合器 在上一篇 ".NET Core 3 WPF MVVM框架 Prism系列之模塊化" 我們留下了一些問題,就是如何處理同模塊不同窗體之間的通信和不同模塊之間不同窗體的通信,Prism提 ...
  • Microsoft Visual Studio 2010 的項目為件改為Microsoft Visual Studio 2015預設打開 2010 的Solution (.Sln) file 更改為 2015 的Solution (.Sln) file ...
  • 設計一個簡單的登錄視窗,要求輸入用戶名:小金,密碼:123456時候點登錄能正確轉到另一個視窗。 1、建立窗體應用。 2、這裡創建一個login和一個NewForm的窗體。 3、在login的窗體拖拉2個label和2個textbox和1個linklabel的控制項。一個標簽名字為用戶名,一個標簽為密 ...
  • 已有站點:HTTP80 %systemroot%\system32\inetsrv\APPCMD ADD APP /SITE.NAME:"HTTP80" /path:/Redirect /physicalPath:"C:\Windows\System32\drivers\etc" /applicat ...
  • ``` var xmlstr = @" some_appid 1413192605 component_verify_ticket some_verify_ticket "; Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; i ...
  • 本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7640873.html,記錄一下學習過程以備後續查用。 一、引言 很多人說原型設計模式會節省機器記憶體,他們說是拷貝出來的對象是原型的複製,不會使用記憶體。我認為這是不對的,因為拷貝出來的每一個對象都是實際 存在的 ...
  • 實現把String字元串轉化為In後可用參數代碼: public string StringToList(string aa) { string bb1 = "("; if (!string.IsNullOrEmpty(aa.Trim())) { string[] bb = aa.Split(new ...
  • 1.ImportData主方法 把傳入為object數組類型,按照下標取出對應的參數,此處為Table和Username public object[] ImportData(object[] Param) { DataTable dt = (DataTable)Param[0]; string m ...
  • C#實現對Excel操作,根據數據的類型不同或者來源不同會放在不同的頁簽中,C#實現添加頁簽代碼如下:(path為文檔保存的地址,dt為要處理的源數據) public void addSheet(string Path, DataTable dt) { var SlDoc = new SLDocum ...
  • public partial class Form1 : Form { public Form1() { InitializeComponent(); Dog dog = new Dog(); InsertDog(dog); dog.OnAlert(); //Console.WriteLine(); ...
x