C#9.0 レコード理解度テスト 《コンストラクタ編》
C#9.0のレコードについて、
理解度を確認する問題を作ってみました。
今回のメインテーマはコンストラクタです。
初回なので、シンプルなコードを揃えています。
息抜きにぜひチャレンジしてください。
問題
次に12例のrecord定義を示します。
それぞれの例について、
「コンパイル可」「コンパイル不可」を答えてください。
「コンパイル不可」と答えた場合は、その理由を答えてください。
環境は以下の通りです
Visual Studio 2019
C#9.0
.NET 5.0
null許容:有効化
基本編
問1
record MyRecord(string Name, int Number)
{
}
問2
record MyRecord()
{
public string? Name { get; init; }
public int Number { get; init; }
}
問3
record MyRecord
{
public string? Name { get; init; }
public int Number { get; init; }
}
引数なしコンストラクタ編
問4
record MyRecord(string Name, int Number)
{
public MyRecord()
{
Name = "Unknown";
Number = 0;
}
}
問5
record MyRecord()
{
public string Name { get; init; }
public int Number { get; init; }
public MyRecord()
{
Name = "Unknown";
Number = 0;
}
}
問6
record MyRecord
{
public string Name { get; init; }
public int Number { get; init; }
public MyRecord()
{
Name = "Unknown";
Number = 0;
}
}
引数ありコンストラクタ編
問7
record MyRecord(string Name, int Number)
{
public MyRecord(string name)
{
Name = name;
}
}
問8
record MyRecord()
{
public string Name { get; init; }
public int Number { get; init; }
public MyRecord(string name)
{
Name = name;
}
}
問9
record MyRecord
{
public string Name { get; init; }
public int Number { get; init; }
public MyRecord(string name)
{
Name = name;
}
}
本体書かない編
問10
record MyRecord(string Name, int Number);
問11
record MyRecord();
問12
record MyRecord;
以上!
模範解答
今回のテーマはコンストラクタの違いでした。
考慮漏れがなかったかどうか確認していきましょう。
基本編
問1: コンパイル可
問2: コンパイル可
問3: コンパイル可
すべてコンパイルできます。
全く同じ定義というわけではなく、new するときに違いがあります。
問1
var r = new MyRecord("なまえ", 123);
問2,問3
var r = new MyRecord() { Name = "なまえ", Number = 123 };
問2,問3、その2
var r = new MyRecord();
問2、問3の例では、プロパティは初期化されないことがあります。
引数なしコンストラクタ編
問4: コンパイル不可
プライマリコンストラクタを呼び出していない。
問5: コンパイル不可
プライマリコンストラクタと定義が衝突している。
問6: コンパイル可
位置指定パラメータ が指定されているレコードでは、 プライマリコンストラクタ が生成されています。
コンストラクタは、基本的にプライマリコンストラクタを呼び出す必要があります。
また、問5では、本体に書いたコンストラクタはシグネチャが衝突してしまい、そもそも定義できません。
以下に、コンパイル可能な修正を示します。
問4修正版
thisを呼び出せばOK
public MyRecord() : this("Unknown", 0)
{
}
引数ありコンストラクタ編
問7: コンパイル不可
プライマリコンストラクタを呼び出していない。
問8: コンパイル不可
プライマリコンストラクタを呼び出していない。
問9: コンパイル可
こちらも、プライマリコンストラクタの呼び出しがテーマになります。
以下に、コンパイル可能な修正を示します。
問7修正版
thisを呼び出せばOK
public MyRecord(string name) : this(name, 0)
{
}
問8修正版
thisを呼び出せばOK
public MyRecord(string name) : this()
{
Name = name;
}
問9はコンパイル可ですが、引数なしのコンストラクタが無いことに注意して下さい。
問3、問6と同じ方法でのnewはコンパイル不可になります。
問9ではNG
var r = new MyRecord() { Name = "なまえ", Number = 123 };
これならOK
var r = new MyRecord("なまえ") { Number = 123 };
問8修正版では、上記2つともnewできます。
本体書かない編
問10: コンパイル可
問11: コンパイル可
問12: コンパイル可
すべてコンパイル可能です。
問11、問12の例が役に立つかどうかはさておき、引数なしのコンストラクタはあるのでnewできます。
newはできる
var r = new MyRecord();
おわりに
本当は『レコードには 位置指定パラメータ を使おう』というような記事を書こうと思っていました。
考えを整理するために色々試し始めたら、挙動の予想が出来ていない部分に気づき、これをまとめるための箸休め的な記事を書くことになりました。
少しでも皆さんの気づきの役に立っていれば幸いです。
次回はもう少し実のある記事を書きたい……
↧