「C Sharpの基礎 - タプル」の版間の差分
細 (Wiki がページ「ValueTupleの使用方法」を「C Sharpの基礎 - ValueTuple」に、リダイレクトを残さずに移動しました) |
細 (Wiki がページ「C Sharpの基礎 - ValueTuple」を「C Sharpの基礎 - タプル」に、リダイレクトを残さずに移動しました) |
(相違点なし)
|
2021年3月5日 (金) 14:13時点における版
概要
専用のクラスや構造体を定義するほどのことでもないが、複数のオブジェクトを一時的に1つに纏めたい時がある。
例えば、今までは、メソッドは1つのオブジェクトしか返せなかったので、複数の結果を返す場合は、複数の結果を格納するためだけに型を定義したり、
あるいは、out引数を使用していた。
.NET Framework 4.7で導入されたValueTuple構造体(System名前空間)とVisual Studio 2017(C#7)で導入されたタプル構文を使えば、
簡単に複数の結果を一時的に1つに纏められる。
ここでは、それらの新しい機能のうち、メソッドから複数の結果を返す方法について解説する。
TupleクラスとValueTuple構造体
Tupleクラスは.NET Fremework 4.0からあり、ValueTuple構造体は.NET Fremework 4.7で導入された。
これら2つはよく似ており、例えば、2つの値をまとめて返すメソッドを次のコードのように記述できる。
// Tupleクラス(.NET Fremework 4.0以降)
static Tuple<int, int> OldExchange(int x, int y) => Tuple.Create(y, x);
// ValueTuple構造体(.NET Fremework 4.7以降)
static ValueTuple<int, int> NewExchange(int x, int y) => ValueTuple.Create(y, x);
複数の値をまとめてメソッドから返す
前述したValueTuple構造体を返すメソッドは、タプル構文を使うと次のように簡潔に書ける。
ValueTuple<int, int>という型の宣言は、タプル構文では(int, int)と同義である。
タプルを生成するValueTuple.Create(y, x)式は、タプル構文では(y, x)と書くだけでよい。
タプル構文でタプル名を付けずに2つの値を返す例
// ValueTuple構造体を直接使う書き方(前述)
static ValueTuple<int, int> NewExchange1(int x, int y) => ValueTuple.Create(y, x);
// タプル構文を使って上と同義のコードを書く
static (int, int) NewExchange1(int x, int y) => (y, x);
上のように記述した場合、戻り値を受け取った側では、タプル内の要素をItem1 / Item2という既定の名前で参照できる。
次のコードのようにしてタプル名を付けると、戻り値を受け取った側ではタプル内の要素をタプル名で参照できる。
なお、タプル名はTupleElementNames属性(System.Runtime.CompilerServices名前空間)によって実現されているが、
この属性を直接コーディングすることはできない。(タプル構文が強制される)
タプル構文でタプル名を付けて2つの値を返す例
static (int x, int y) NewExchange2(int x, int y) => (y, x);
上のように記述した場合、戻り値を受け取った側では、タプル内の要素をx / yというタプル名で参照できる。
適切なタプル名を付けておくことで、可読性が良くなる。
複数の値をメソッドから受け取る
ValueTuple構造体を返すメソッドの基本的な呼び出し方は、次のコードのようになる。
// タプル名なし(既定の名前Item1 / Item2等でアクセスする)
var tResult1 = NewExchange1(2, 3);
WriteLine($"tResult1.Item1={tResult1.Item1}, tResult1.Item2={tResult1.Item2}");
// タプル名付き
var tResult2 = NewExchange2(2, 3);
WriteLine($"tResult2.x={tResult2.x}, tResult2.y={tResult2.y}");
あるいは、次のコードのように、受け取るときに別のタプル名を付けることもできる。
// タプル名なしで返すメソッド
(int X, int Y) tResult1 = NewExchange1(2, 3);
WriteLine($"tResult1.X={tResult1.X}, tResult1.Y={tResult1.Y}");
// タプル名付きで返してくるメソッド
(int M, int N) tResult2 = NewExchange2(2, 3);
WriteLine($"tResult1.X={tResult1.M}, tResult1.Y={tResult1.N}");
更に、C# 7では、タプルを受け取るときにいきなり分解することも可能である。(タプルの要素を個別の変数に代入する)
var (p, q) = NewExchange1(2, 3);
WriteLine($"p={p}, q={q}");
また、(p, _)のようにして、タプルとして返された値で使わない要素を「_」で示すこともできる。(「_」は書き込み専用の変数)
var (p, _) = NewExchange1(2, 3);
WriteLine($"p={p}");