[料理佳餚] 用 ValueTuple 解放雞肋類別

  • 1504
  • 0
  • C#
  • 2019-08-30

我們呼叫一個函式原則上以回傳一個結果為優,偶爾像 int.TryParse 使用 out 修飾詞,或是使用 Tuple 類別 來多吐一些結果,不過這些都不如將多個結果封裝成一個類別還來的合適,但是如果私有函式有回傳多個結果的需求,為此定義一個類別就顯得有些雞肋,除了要取一個適當的名字之外,還要定義它的存取限制,把它弄成 public 也不是,弄成 private 放在當前類別裡面又覺得「嘖...」。

幸好,從 C# 7.0 開始支援 ValueTuple Struct,它是 ValueType,可以用來解放這種雞肋類別。

須額外從 NuGet 上安裝 System.ValueTuple package

底下我用一個範例來說明,我有一個 XML 檔,根節點底下的每個節點都有 TypePattern 屬性。

<?xml version="1.0" encoding="utf-8" ?>
<Root>
  <Node Type="abc" Pattern="abc-(\d+)" />
  <Node Type="edf" Pattern="def-(\d+)" />
  <Node Type="other" Pattern=".*" />
</Root>

我輸入一字串,透過 Regular Expression 比對 Pattern 屬性值,比中之後除了回傳該節點之外,還要回傳 Match 結果,我就用 ValueTuple 來寫這一段程式。

private (XElement, Match) FindNode(string input)
{
    var xdoc = XDocument.Parse("...");

    foreach (var descendant in xdoc.Root.Descendants())
    {
        var match = Regex.Match(input, descendant.Attribute("Pattern").Value);

        if (match.Success) return (descendant, match);
    }

    return (null, null);
}

呼叫端接收回傳值的變數型別宣告就像下面一樣,而 ValueTuple 最關鍵的作用就在於我可以為這些回傳值重新命名。

甚至回傳值的名稱在函式宣告的時候就可以指定了

ValueTuple 的 Unboxing

我再增加一個程序,就是將找到的節點用 ObjectCache 快取起來,不必再到 XDocument 中再找一次,但是 ObjectCache 回傳的是 object 類別,我們就需要強制轉型。

ValueTuple 的序列化要謹慎

我們額外對回傳值的命名都是虛的,在編譯後都會被取代成 Item1、Item2、...,除非大家講好用 Item1、Item2、... 來識別,不然最好不要直接拿 ValueTuple 去序列化。

相關資源

C# 指南
ASP.NET 教學
ASP.NET MVC 指引
Azure SQL Database 教學
SQL Server 教學
Xamarin.Forms 教學