38
29

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.

ValueTupleをTuple・匿名型と比較してみる

Last updated at Posted at 2017-05-17

#概要
C#7で導入されたValueTupleをそれまでのTupleや匿名型と比較してみました。

ValueTuple Tuple 匿名型
名前付け ×
引数・戻値 ×
型の種類 構造体 クラス クラス
メンバの種類 フィールド プロパティー プロパティー
不変性 ミュータブル イミュータブル イミュータブル

##名前付け
ValueTupleと匿名型はメンバに名前を付けることができます。
ただし、匿名型と異なりValueTupleは初期化時の変数名等から名前を割り当てることはできません。

// ValueTuple
var vt = (x:1, y:"vt");
// 匿名型
var a = new { x = 1, y = "a" };

var x = 1;
var y = "yy";

// ValueTupleでは名前がつかない
var vt2 = (x, y);
// 名前を付けるためは、ちゃんと名前を書かないとダメ
var vt2_ = (x:x, y:y);

// 匿名型では名前がつく
var a2 = new { x, y };

// 明示的に名前付きのValueTupleとしても宣言可能
(int x, string y) vt3 = (1, "ccc");

##引数・戻値
Tupleと同様ValueTupleも引数・戻値としての利用が可能です。もちろん名前付きで利用できます。

// Tupleは引数・戻値に利用できます。
public Tuple<int, string> GetTuple(Tuple<int, string> t) => t;
// ValueTupleも、引数にも、戻り値にも利用可能です。
public (int, string) GetValueTuple((int, string) vt) => vt;
// もちろん名前を付けることも
public (int x, string y) GetValueTuple2((int i, string s) vt) => vt;

##型の種類
ValueTupleは値型です。

// structなので、null初期化できない
// Null 非許容の値型であるため、Null を '(int, string)' に変換できません
(int, string) vt = null;

// classなのでnull初期化可能
Tuple<int, string> t = null;

##メンバの種類
ValueTupleのメンバは、プロパティーではなくフィールドです。そのため、

  • out/refの引数に渡すことができます。
  • Propertyを前提としたFwでは利用不可です。(例えばBinding)
var vt = (1, "a");
Add(ref vt.Item1);

var t = Tuple.Create(1, "a");
// プロパティまたはインデクサーを out か ref のパラメーターとして渡すことはできません。
Add(ref t.Item1);

##不変性
ValueTupleのメンバがフィールドであるため、不変にはなりえません。

// 割り当て可能
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;

なお、不変ではないものの値型であるため、以下のようなコードは記述できません。

(int i, string s)[] arr =
{
    (1, "a"),
    (2, "b"),
    (3, "c"),
    (4, "d"),
};

foreach (var tuple in arr)
{
    // 'tuple' のメンバーは 'foreach 繰り返し変数' であるため変更できません
    tuple.i = 2;
}

値型はimmutableにすべきっていうのがClassLibrary設計の指針だった気がするのですが。

##追記
BuildInsiderに解説記事上がりました。

「C# 7のタプルが一般的なガイドラインに沿わずに書き換え可能な構造体である背景」
http://www.buildinsider.net/column/iwanaga-nobuyuki/016

38
29
0

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
38
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?