1. 程式人生 > >C#的未來:元組及匿名結構體

C#的未來:元組及匿名結構體

【IT168 技術】隨著C# 6接近完成,C# 7的開發計劃也開始提到了日程上。雖然目前為止,還沒有任何可確定的內容,但C# 團隊已經開始按照“興趣及預計可行性”將各種提議進行分類。在這個系列文章中,我們將對某些提議進行分析,首先從對元組的語言支援開始。

  使用元組的目標是以一種輕量級的方式從一個函式中返回多個值。對元組的良好支援能夠消除對out引數的使用,這種引數通常被認為是一種笨重的方案。此外,out引數無法相容 async/await,因此在許多場景中out引數將變得毫無作用。

  元組類存在什麼問題?

  從.NET Framework 4開始,就加入了Tuple(元組)這個類。但是多數開發者都認為這個類只在非常有限的場景中才能夠體現出實用性。首先,元組是一個類,這意味著在使用時必須為它分配

記憶體,而這一點會增加記憶體的壓力,並使垃圾回收器的執行週期變得更加頻繁。如果要讓元組與out引數在效能方面進行競爭,需要將其實現為一個結構體。

  第二個問題與 API 的設計有關,如果你看到了某個返回型別Tuple<int, int>,那麼從型別本身你無法瞭解任何資訊。如此一來,在使用這個函式的過程中你至少需要檢查文件兩次,一次是在編寫函式時,另一次則是在程式碼審查時。如果返回型別能夠表現為類似於Tuple<int count, int sum>這樣,那麼它的實用性將會大大增加。

  匿名結構體

  考慮一下以下程式碼:

  public (int sum, int count) Tally (IEnumerable<int> values) { ... }

  var t = new (int sum, int count) { sum = 0, count = 0 };

  在這條提議中,以上每一行程式碼都將定義一個新的匿名值型別,其中包括sum和count屬性。需要注意的是,和匿名類不同,匿名結構體要求你明確地列舉出屬性的名稱與型別。

  使用結構體的一個好處在於它們會自動定義Equals和GetHashCode方法。不過也有人會表示預設的實現方式不夠高效,編譯器應當替換它的實現。

  分解元組

  關於元組的提議中有一個重要的部分,即應當能夠通過一行程式碼對元組進行分解。考慮一下下面的程式碼塊:

  var t = Tally (myValues);

  var sum = t.Sum;

  var count = t.Count;

  使用分解功能,這段程式碼就能夠進行簡化:

  (var sum, var count) = Tally (myValues);

  目前還沒有決定是否能夠在不定義新變數的提前下對元組進行分組。或者換句話說,能否省略“var”的使用,而代之以某個已經存在的本地變數。

  返回元組

  關於如何從某個函式中返回元組型別這一點,有兩條提議正在考慮中。第一條提議非常容易理解:

  return (a, b);

  而第二條提議的方式將完全不使用return語句。考慮一下這個示例:

  public (int sum, int count) Tally (IEnumerable<int> values)

  {

      sum = 0; count = 0;

  foreach (var value in values) { sum += value; count++; }

  }

  隱式建立的本地及返回變數並不是一種新的概念,Visual Basic最初的設計就是這樣的,只是在VB 7中引入了返回語句之後,這種方法才逐漸變得不流行了。這種寫法也類似於使用out引數的方式。不過,對於許多開發者來說,在函式中看不到返回語句總是讓他們感覺有些不安。

  其它問題

  對元組的支援是一個比看上去還要複雜的主題。雖然本文目前討論的主要是日常的使用方式,但還有許多細節需要從編譯器的作者以及高階使用場景的角度進行處理。

  元組是否應該作為可變型別?從效能及便利性的角度考慮,這種選擇具有一定實用性,但這有可能讓程式碼變得更容易出錯,尤其是在處理多執行緒的情況下。

  元組是否應該跨多個程度集進行統一化?匿名型別並不是統一的,但元組與匿名型別不同,它們可以作為API的一部分向外部暴露。

  元組能否被轉型為其它元組?表面上看,如果兩個元組具有相同的型別結構,但具有不同的屬性名稱。或者具有相同的屬性名稱,但屬性的型別更寬泛,那麼這種轉換應該是可以接受的。

  如果你將某個具有兩個值的元組作為引數傳遞給某個接受兩個引數的函式,那麼是否應該將元組進行自動分解(攤平)呢?反過來,你能夠“反分解”某個引數對,將其合併為某個元組引數嗎?