レコードのはじめの一歩
この記事では、C#9.0で追加されたレコードを、主に初心者向けに解説します。
note:この記事では、C#9.0で追加された
record
によるデータ構造を取り扱います。
データベースの話題はこの記事では扱いませんのでご注意ください。
C#10 では 当記事で扱う
record
はrecord class
と書くこともできるようになりました。
C#10で追加された、レコード構造体record struct
についてはこの記事では扱っていません。
レコードの定義
「どのような値を順番に持つかを決めて、そのデータ構造に名前を付ける」のがレコードの機能です。
record MyData(string Name, int Number);
上のようにMyData
という名前のレコードを定義することができます。
class
を定義するのと同じ階層に定義しましょう。
格納する値を指定している (string Name, int Number)
の部分を「位置指定パラメータ」と呼びます。
note: はじめは、「位置指定パラメータ」に、
int
,double
,string
などの基本的な型の組み合わせを使いましょう。
配列や独自のクラスなどを指定したい場合は、後半の注意点も確認してください。
インスタンスの生成
定義通りの順番に実際の値を格納したインスタンス(実体)を生成できます。
MyData data1 = new MyData("なまえ", 123);
レコードのインスタンスは、以下のような性質を持っています。
- 値を読み取ることができる
- 値を書き換えることができない
- 一部を書き換えたコピーを作ることができる
string a = data1.Name;
int b = data1.Number;
(string x, int y) = data1;
MyData data2 = data1 with { Number = 234 };
with
式は、C#9.0時点ではレコードの特徴的な機能の一つです。
with
式の機能は今後拡張される予定です。
比較、文字列化
レコードでは、格納した値をいっぺんに比較できます。
if(data1 == data2) {
/* NameとNumberがすべて一致したら何かの処理を行う */
}
また、レコードではプロパティの中身まで文字列化してくれます。
Console.WriteLine(data1);
// 出力=> "MyData { Name = なまえ, Number = 123 }"
これらの機能は、クラスでも自分で実装することで可能です。
レコードはこの面倒な実装を勝手にやってくれます。
基本はここまで
レコードの基本の使い方はここまでです。
ここからは追加の説明になります。
レコードのメンバー追加
クラスと同じように、レコードにもメソッドなどのメンバーを追加することもできます。
record MyAdvanceData(string Name, int Number) {
/* こうやってメソッドなどを定義することもできる */
}
ただ、ある程度のメンバーを定義しないと役に立たないクラスと違って、レコードでは「位置指定パラメータ」を指定するだけで十分に役に立ちます。
不要な場合は 何も書かない方が良い でしょう。
ここにメンバーを追加する例は、また別の記事で書くつもりです。
注意点
「値を書き換えることができない」と書きましたが、「位置指定パラメータ」で指定した 型の種類によっては注意が必要 です。
例えば、配列のような書き換え可能な型は、以下のような書き換えができてしまいます。
record MyArrayData(int[] Values);
int[] array = new int[] { 2, 3, 5, 8 };
MyArrayData data = new MyArrayData(array);
// 配列の中身の書き換えはdataの中身も書き換えてしまう。
array[1] = 10;
// 格納した後の配列内の値を書き換えることができてしまう。
data.Values[2] = 13;
また、比較に関しては、配列の中身まで比較されることはありません。
こういうレコードの定義の良し悪しは、簡単に断定できるものではありませんが、「レコード型に格納したからといって、 不変な性質が追加されるわけではない 」という事は頭に入れておいてください。
不変な性質を保ちつつ配列を格納するレコードの例は、別の記事で書くつもりです。
不変な配列やリストについて、参考までに↓
使いこなせていなかった System.Collections.Immutable"
おわりに
クラスとレコードで、できる事はそんなに大きく違うわけではありませんが、「変更しない値を保持することが主な目的」で「複雑な機能を必要としない」ならば、レコードは選択肢に入ります。
まずは、レコードらしい基本的な使い方が出来そうな場面から使ってみてください。
複雑なレコードの使い方もできますし、そういうサンプルを私も公開する予定ですが、 シンプルな使い方こそがレコードの最大の魅力 だと思っています。
Qiitaに限らず、レコードの紹介記事ではレコードを使う意味がほとんど無いサンプルを時折見かけます。
多くの場合、メンバーを書き換えすぎていることが原因のように思います。
「メンバーの追加定義や書き換えはしなくてもいいんだよ」ということが、この記事で伝われば幸いです。