C#のデコンストラクトとは?
C#を書いていると、次のようなコードを見かけることがあります。
var (name, age) = ("Taro", 20);
この var (name, age) のような書き方は、デコンストラクト(Deconstruct) と呼ばれる機能です。
最初は少し特殊に見えますが、意味が分かるとかなり便利です。
この記事では、C#のデコンストラクトについて、基本から使いどころ、注意点までわかりやすく解説します。
デコンストラクトとは
デコンストラクトとは、1つの値やオブジェクトを複数の変数に分解して代入する仕組みです。
たとえば、タプルの値をまとめて受け取るだけでなく、個別の変数に分けて受け取れます。
var person = ("Taro", 20);
(string name, int age) = person;
Console.WriteLine(name); // Taro
Console.WriteLine(age); // 20
このように、person という1つの値を name と age に分解して代入できます。
まずはタプルで理解する
デコンストラクトは、まずタプルと一緒に覚えるのがわかりやすいです。
通常の受け取り方
var person = ("Taro", 20);
Console.WriteLine(person.Item1);
Console.WriteLine(person.Item2);
これでも値は取り出せますが、Item1 や Item2 は少し読みづらいです。
デコンストラクトを使った受け取り方
var person = ("Taro", 20);
var (name, age) = person;
Console.WriteLine(name);
Console.WriteLine(age);
こちらの方が、何の値を扱っているのかが分かりやすくなります。
戻り値を複数受け取りたいときに便利
デコンストラクトは、メソッドの戻り値を複数返したいときによく使われます。
var (id, name) = GetUser();
Console.WriteLine(id);
Console.WriteLine(name);
static (string Id, string Name) GetUser()
{
return ("001", "Taro");
}
DTOを作るほどではない小さな処理で、手軽に複数の値を返したいときに便利です。
クラスでもデコンストラクトできる
デコンストラクトはタプルだけでなく、クラスや構造体にも対応できます。
そのためには、Deconstruct メソッドを定義します。
サンプル
public class User
{
public string Name { get; set; }
public int Age { get; set; }
public void Deconstruct(out string name, out int age)
{
name = Name;
age = Age;
}
}
これで次のように書けます。
var user = new User
{
Name = "Taro",
Age = 20
};
var (name, age) = user;
Console.WriteLine(name); // Taro
Console.WriteLine(age); // 20
Deconstruct メソッドの意味
Deconstruct メソッドは、オブジェクトをどう分解するかを定義するメソッドです。
public void Deconstruct(out string name, out int age)
{
name = Name;
age = Age;
}
out 引数に分解後の値を設定することで、呼び出し側は次のように書けます。
var (name, age) = user;
つまり、var (name, age) = user; という構文の裏で、user.Deconstruct(...) が呼ばれているイメージです。
不要な値は _ で無視できる
デコンストラクトでは、使わない値を _ で無視できます。
var (name, _) = ("Taro", 20);
Console.WriteLine(name); // Taro
このように、必要な値だけを受け取りたいときに便利です。
クラスでも同じように使えます。
var (name, _) = user;
型を明示することもできる
var を使うことが多いですが、型を明示して書くこともできます。
(string name, int age) = ("Taro", 20);
ただし、通常は var の方が読みやすいことが多いです。
var (name, age) = ("Taro", 20);
実務での使いどころ
デコンストラクトは便利ですが、どこでも使えばよいわけではありません。
実務では、次のような場面で使いやすいです。
1. 複数の戻り値を返したいとき
var (success, message) = Validate(input);
簡単な成否判定や、値とメッセージを返したいときに便利です。
2. 一時的なデータの分解
var (year, month, day) = GetTargetDate();
小さな処理の中で、一時的に値を分けて使いたいときに向いています。
3. クラスの一部だけを簡潔に取り出したいとき
var (name, age) = user;
オブジェクトの全体ではなく、一部の主要な値だけ使いたい場合に読みやすくなります。
注意点
便利なデコンストラクトですが、使うときには注意点もあります。
1. 順番に依存する
デコンストラクトは名前ではなく順番で値が入ります。
public void Deconstruct(out string name, out int age)
{
name = Name;
age = Age;
}
この順番で受け取るため、もし順番を間違えると意図しない代入になります。
2. 多用すると逆に読みにくい
短い処理では便利ですが、値が多すぎると逆に読みにくくなります。
var (a, b, c, d, e, f) = someObject;
このように要素が多い場合は、通常のプロパティ参照やDTOの方が分かりやすいこともあります。
3. クラスでは Deconstruct の実装が必要
タプルはそのまま使えますが、クラスや構造体では自分で Deconstruct メソッドを定義する必要があります。
DTOとの使い分け
複数の値を返したい場合、デコンストラクトとDTOのどちらを使うべきか迷うことがあります。
私のおすすめは、次のような使い分けです。
デコンストラクトが向いているケース
- 一時的な値の受け渡し
- 小さな処理
- 戻り値が2〜3個程度
- 意味が明確な値の組み合わせ
DTOが向いているケース
- 項目数が多い
- 長期的に保守するAPIや業務処理
- 項目名を明確に持たせたい
- 可読性や拡張性を重視したい
たとえば、Web APIのレスポンスや業務データはDTOの方が無難なことが多いです。
一方で、内部処理の軽い戻り値にはデコンストラクトが便利です。
サンプル:よくある実装例
バリデーション結果を返す
var (isValid, errorMessage) = ValidateUserName("");
if (!isValid)
{
Console.WriteLine(errorMessage);
}
static (bool IsValid, string ErrorMessage) ValidateUserName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return (false, "ユーザー名を入力してください。");
}
return (true, string.Empty);
}
クラスに対して使う
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public void Deconstruct(out int id, out string name)
{
id = Id;
name = Name;
}
}
var product = new Product
{
Id = 100,
Name = "Keyboard"
};
var (id, name) = product;
Console.WriteLine(id); // 100
Console.WriteLine(name); // Keyboard
まとめ
C#のデコンストラクトは、1つの値やオブジェクトを複数の変数に分解して受け取るための機能です。
特にタプルと相性がよく、複数の戻り値を簡潔に扱いたいときに便利です。
また、クラスに Deconstruct メソッドを実装すれば、独自の型でも同じように使えます。
ただし、項目数が多い場合や長期保守を前提とする場合は、DTOの方が読みやすいこともあります。
便利だからこそ、使いどころを見極めることが大切です。
おわりに
デコンストラクトは、C#に慣れてくると「あると嬉しい」機能の1つです。
最初はタプルから使い始めると理解しやすいと思います。
普段のコードで、
- 複数の戻り値を返したい
- 少ない値をまとめて扱いたい
- 少しだけコードをすっきりさせたい
という場面があれば、試してみる価値はあります。