11
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-06-26

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

ちなみに、.NETFramework4.0以上ならタプルは使用可能。
7や8.1向けのアプリケーションにtupleを組み込みたい場合は、NuGetからSystem.ValueTupleをダウンロードすると良い。
image.png

「タプル」の原義については、Wikipedia先生が詳しいのでそちらに譲る事にする。

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

// 何の数字かはお察しください...
var tuple = ("鍵山雛", 50, 45, 49);

という感じである。
簡易二次元配列とか簡易クラスと捉えるとしっくりくるかも。

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

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クラスのオブジェクトの配列がある。

// 数値については異論を認める
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 = "東方風神録"
  }
};

さて、ここからプライベートプロパティを取り出す実装をするという事を考えてみる。

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

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

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

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

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

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

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

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でセットできるようになる。

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

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

#ちょっと応用

分解

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

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

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

オブジェクトっぽく扱う

Listにもできる。工夫次第ではJavaのLinkedHashMapみたいなアレもできる。

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で抽出とかも簡単にできる。

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

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

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

11
12
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?