C#7で東方を例にタプルを使って実装サンプルを作ってみる

#タプルってなんだべ。んめもんだか？
VisualStudio2017のC#(C# Ver7.0)から本格的に組み込まれた、「タプル(Tuple)」。
大変便利で、拙作ソフトウェアでは結構多用しているが、まだあまりピンと来ない人がまだ多そうなので、東方っぽい例を出しながら紹介していきたいと思う。

ちなみに、.NETFramework4.0以上ならタプルは使用可能。
7や8.1向けのアプリケーションにtupleを組み込みたい場合は、NuGetからSystem.ValueTupleをダウンロードすると良い。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158353/c7fea390-38ca-af0a-d68a-eacc69e318e7.png)

「タプル」の原義については、[Wikipedia先生が詳しい](https://ja.wikipedia.org/wiki/%E3%82%BF%E3%83%97%E3%83%AB)のでそちらに譲る事にする。

##つまりどういうことなんだってばよ？
簡単に言えば、**複数の値をペアにして扱える構文**である。

```c#
// 何の数字かはお察しください...
var tuple = ("鍵山雛", 50, 45, 49);
```
という感じである。
**簡易二次元配列**とか**簡易クラス**と捉えるとしっくりくるかも。

#基本的な使い方
例えば、こういうアヤシイクラスがあったとしよう。

```C#:Character.cs
public class Character {
  public string Name { get; set; }
  public string Category { get; set; }
  private int Tall;
  private int Bust;
  private int Waist;
  private int Hip;

  public Character(int t, int b, int w, int h) {
    Tall = t;
    Bust = b;
    Waist = w;
    Hip = h;
  }
}
```
そして、これまたアヤシイCharacterクラスのオブジェクトの配列がある。

```C#
// 数値については異論を認める
var Fujinroku = new Character[] {
  new Character(162, 84, 52, 83) {
    Name = "秋静葉",
    Category = "東方風神録"
  },
  new Character(163, 94, 62, 81) {
    Name = "秋穣子",
    Category = "東方風神録"
  },
  new Character(172, 94, 57, 89) {
    Name = "鍵山雛",
    Category = "東方風神録"
  },
  new Character(161, 88, 52, 91) {
    Name = "河城にとり",
    Category = "東方風神録"
  },
  new Character(165, 86, 64, 83) {
    Name = "犬走椛",
    Category = "東方風神録"
  },
  new Character(169, 92, 55, 88) {
    Name = "射命丸文",
    Category = "東方花映塚"
  }
  new Character(168, 94, 65, 94) {
    Name = "東風谷早苗",
    Category = "東方風神録"
  },
  new Character(176, 88, 60, 88) {
    Name = "八坂神奈子",
    Category = "東方風神録"
  }
  new Character(152, 79, 52, 80) {
    Name = "洩矢諏訪子",
    Category = "東方風神録"
  }
};
```
さて、ここからプライベートプロパティを取り出す実装をするという事を考えてみる。

従来のやり方では、きっとこうだろう。

```C#
// 一つずつGetterを作るのは面倒だよね
public int GetTall() {
  return Tall;
}
```

タプルを使うと、こういうことができる。

```C#
// プロパティを根こそぎ浚える
public (int, int, int) GetThreeSize() {
  return (Bust, Waist, Hip);
}
```

つまり、例の配列から雛ちゃんのスリーサイズを得るには、こうする。

```C#
var HinaChangNoThreeSize = Fujinroku[2].GetThreeSize();
```

##セッターにも使えるぞ
Getが出来るってことは、当然Setも出来る。
さっきのアヤシイクラスを拡張して、

```C#:CharacterWithColors.cs
public class CharacterWithColors : Character {
  private string Hair;
  private string Eye;
  private string Pants;

  public void SetColor((string, string, string) colors) {
    Hair = colors.Item1;
    Eye = colors.Item2;
    Pants = colors.Item3;
  }
}
```

とすれば、髪の色、目の色、おぱんつの色をTupleでセットできるようになる。

```C#
var UdonChang = new CharacterWithColors(173, 92, 56, 84) {
  Name = "鈴仙・優曇華院・イナバ",
  Category = "東方永夜抄"
}

// ぱんつはいてません
UdonChang.SetColor(("#DA81F5", "#FE2E2E", null));
```

#ちょっと応用
## 分解
C#7.0以降では、タプルの値を簡単に分解できるようになった。~~値ってば最強ね~~
例えば、さっきの雛ちゃんのスリーサイズをint３つにバラすには、こうする。

```C#
// ローカル変数と同じ扱いなので、雛ちゃんのスリーサイズは同一スコープ内で利用できる
(int Bust, int Waist, int Hip) = HinaChangNoThreeSize;

// 直接メソッドから取ることもできる
(Bust, Waist, Hip) = Fujinroku[2].GetThreeSize();
```

## オブジェクトっぽく扱う
Listにもできる。工夫次第ではJavaのLinkedHashMapみたいなアレもできる。

```C#
var tupleList = new List<(int, Character)>();

// 世界一位
tupleList.Add((1, new Character(171, 89, 52, 88) {
  Name = "博麗霊夢",
  Category = "自機"
}));

// 悔しいので来年は抜いてやるぜ
tupleList.Add((2, new Character(167, 84, 57, 90) {
  Name = "霧雨魔理沙",
  Category = "自機"
}));
 :
 :
// ⑨位でいいの。謙虚だもの私
tupleList.Add((9, new Character(174, 92, 63, 91) {
  Name = "アリス・マーガトロイド",
  Category = "東方妖々夢"
}));
 :
 :
```

## Linqで使う
タプルの配列はLinqで抽出とかも簡単にできる。

```C#
// int, Characterのタプルリストから上位10キャラの名前を取得
tupleList.Where(tuple => tuple.Item1 <= 10).Select(tuple => tuple.Item2.Name);

/*
  今年のサンプルだと、
  ---
  博麗霊夢
  霧雨魔理沙
  古明地こいし
  魂魄妖夢
  十六夜咲夜
  フランドール・スカーレット
  レミリア・スカーレット
  古明地さとり
  アリス・マーガトロイド
  藤原妹紅
  ---
　となる。
*/
```

#まとめ
**あれっ、もうDictionaryオワコンじゃね……？**