我們呼叫一個函式原則上以回傳一個結果為優,偶爾像 int.TryParse 使用 out 修飾詞,或是使用 Tuple 類別 來多吐一些結果,不過這些都不如將多個結果封裝成一個類別還來的合適,但是如果私有函式有回傳多個結果的需求,為此定義一個類別就顯得有些雞肋,除了要取一個適當的名字之外,還要定義它的存取限制,把它弄成 public 也不是,弄成 private 放在當前類別裡面又覺得「嘖...」。
幸好,從 C# 7.0 開始支援 ValueTuple Struct,它是 ValueType,可以用來解放這種雞肋類別。
須額外從 NuGet 上安裝 System.ValueTuple package
底下我用一個範例來說明,我有一個 XML 檔,根節點底下的每個節點都有 Type
、Pattern
屬性。
<?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 去序列化。