MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
C Sharpの基礎 - タプルのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
C Sharpの基礎 - タプル
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == 専用のクラスや構造体を定義するほどのことでもないが、複数のオブジェクトを一時的に1つに纏めたい時がある。<br> <br> 例えば、今までは、メソッドは1つのオブジェクトしか返せなかったので、複数の結果を返す場合は、複数の結果を格納するためだけに型を定義したり、<br> あるいは、out引数を使用していた。<br> <br> .NET Framework 4.7で導入されたValueTuple構造体(System名前空間)とVisual Studio 2017(C# 7)で導入されたタプル構文を使えば、<br> 簡単に複数の結果を一時的に1つに纏められる。<br> ここでは、それらの新しい機能のうち、メソッドから複数の結果を返す方法について解説する。<br> <br><br> == TupleクラスとValueTuple構造体の比較 == <center> {| class="wikitable" style="background-color:#fefefe;" |- ! style="background-color:#00ffff;" | ! style="background-color:#00ffff;" | Tupleクラス ! style="background-color:#00ffff;" | ValueTuple構造体 ! style="background-color:#00ffff;" | 匿名型 |- | 名前付け || × || ○ || ○ |- | 引数・戻り値 || ○ || ○ || × |- | 型の種類 || クラス || 構造体 || クラス |- | メンバの種類 || プロパティ || フィールド || プロパティ |- | 不変性 || イミュータブル || ミュータブル || イミュータブル |} </center> <br> ==== 名前付け ==== <code>ValueTuple</code>構造体と匿名型は、メンバに名前を付けることができる。<br> ただし、匿名型と異なり、<code>ValueTuple</code>構造体は初期化時の変数名等から名前を割り当てることはできない。<br> <syntaxhighlight lang="c#"> var hoge = 1; var piyo = "yy"; // ValueTuple構造体 var vt1 = (x:1, y:"vt"); var vt2 = (x:hoge, y:piyo); (int x, string y) vt3 = (1, "ccc"); // 明示的に、名前付きのValueTuple構造体として宣言できる // 匿名型 var a1 = new {x = 1, y = "a"}; var a2 = new {hoge, piyo}; </syntaxhighlight> <br> ==== 引数・戻値 ==== <code>Tuple</code>クラスと同様、<code>ValueTuple</code>構造体も引数・戻値として指定できる。<br> <syntaxhighlight lang="c#"> // 引数・戻り値にTupleクラスを指定する public Tuple<int, string> GetTuple(Tuple<int, string> t) => t; // 引数・戻り値にValueTuple構造体を指定する public (int, string) GetValueTuple1((int, string) vt) => vt; // 引数・戻り値に名前付きValueTuple構造体を指定する public (int x, string y) GetValueTuple2((int a, string b) vt) => vt; </syntaxhighlight> <br> ==== 型の種類 ==== <code>Tuple</code>クラスは、null許容であるため、<code>null</code>で初期化できる。<br> <code>ValueTuple</code>構造体は、null非許容の値型であるため、<code>null</code>で初期化できない。<br> <syntaxhighlight lang="c#"> // null非許容の値型であるため、nullを '(int, string)' に変換できません (int, string) vt = null; // Tupleクラスは、nullで初期化できる Tuple<int, string> t = null; </syntaxhighlight> <br> ==== メンバの種類 ==== <code>ValueTuple</code>構造体のメンバはフィールドであるため、以下の2つの特徴がある。<br> * out / refキーワードの引数に渡すことができる。 * プロパティを前提としたFWでは使用できない。(例. バインディング等) <syntaxhighlight lang="c#"> var vt = (1, "a"); Add(ref vt.Item1); var t = Tuple.Create(1, "a"); // Add(ref t.Item1); // プロパティまたはインデクサをout / refキーワードの引数に渡すことはできない </syntaxhighlight> <br> ==== 不変性 ==== <code>Tuple</code>クラスのプロパティは、イミュータブル(不変)である。<br> <code>ValueTuple</code>構造体のメンバはフィールドであるため、ミュータブルである。<br> <syntaxhighlight lang="c#"> // 割り当て可能 var vt = (1, "a"); vt.Item1 = 2; // Tuple<int, string>.Item1(プロパティまたはインデクサ)は読み取り専用であるため、割り当てることはできない var t = Tuple.Create(1, "a"); // t.Item1 = 2; // <anonymous type: int Item1, string Item2>.Item1(プロパティまたはインデクサ)は読み取り専用であるため、割り当てることはできない var a = new { Item1 = 1, Item2 = "a" }; // a.Item1 = 2; </syntaxhighlight> <br> なお、<code>ValueTuple</code>構造体のフィールドはミュータブルであるが値型でもあるため、以下のように記述できない。<br> <syntaxhighlight lang="c#"> (int i, string s)[] arr = { (1, "a"), (2, "b"), (3, "c"), (4, "d")}; foreach(var tuple in arr) { // tuple.i = 2; // コンパイルエラー // ValueTuple構造体のフィールドは、foreach文の繰り返し変数であるため変更できない } </syntaxhighlight> <br><br> == TupleクラスとValueTuple構造体 == Tupleクラスは.NET Fremework 4.0からあり、ValueTuple構造体は.NET Fremework 4.7で導入された。<br> これら2つはよく似ており、例えば、2つの値をまとめて返すメソッドを次のコードのように記述できる。<br> <source lang="c#"> // 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); </source> <br><br> == 複数の値をまとめてメソッドから返す == 前述したValueTuple構造体を返すメソッドは、タプル構文を使うと次のように簡潔に書ける。<br> ValueTuple<int, int>という型の宣言は、タプル構文では(int, int)と同義である。<br> タプルを生成するValueTuple.Create(y, x)式は、タプル構文では(y, x)と書くだけでよい。<br> <source lang="c#"> タプル構文でタプル名を付けずに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); </source> 上のように記述した場合、戻り値を受け取った側では、タプル内の要素をItem1 / Item2という既定の名前で参照できる。<br> <br> 次のコードのようにしてタプル名を付けると、戻り値を受け取った側ではタプル内の要素をタプル名で参照できる。<br> なお、タプル名はTupleElementNames属性(System.Runtime.CompilerServices名前空間)によって実現されているが、<br> この属性を直接コーディングすることはできない。(タプル構文が強制される)<br> <source lang="c#"> タプル構文でタプル名を付けて2つの値を返す例 static (int x, int y) NewExchange2(int x, int y) => (y, x); </source> 上のように記述した場合、戻り値を受け取った側では、タプル内の要素をx / yというタプル名で参照できる。<br> 適切なタプル名を付けておくことで、可読性が良くなる。<br> <br><br> == 複数の値をメソッドから受け取る == ValueTuple構造体を返すメソッドの基本的な呼び出し方は、次のコードのようになる。<br> <source lang="c#"> // タプル名なし(既定の名前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}"); </source> あるいは、次のコードのように、受け取るときに別のタプル名を付けることもできる。<br> <source lang="c++"> // タプル名なしで返すメソッド (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}"); </source> <br> 更に、C# 7では、タプルを受け取るときにいきなり分解することも可能である。(タプルの要素を個別の変数に代入する)<br> <source lang="c#"> var (p, q) = NewExchange1(2, 3); WriteLine($"p={p}, q={q}"); </source> <br> また、(p, _)のようにして、タプルとして返された値で使わない要素を「_」で示すこともできる。(「_」は書き込み専用の変数)<br> <source lang="c#"> var (p, _) = NewExchange1(2, 3); WriteLine($"p={p}"); </source> <br><br> __FORCETOC__ [[カテゴリ:C_Sharp]]
C Sharpの基礎 - タプル
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse