C# コンパイラ エラー CS9043 について解説: ref returning プロパティと required 修飾子の組み合わせ問題
コンパイラエラー CS9043は、ref返却プロパティにrequired修飾子を指定した際に発生します。
オブジェクト初期化時にメンバー設定が求められますが、ref返却プロパティにはsetterが存在しないため、この組み合わせは使用できません。
エラーを解消するには、値渡しの通常プロパティにリファクタリングする方法が推奨されます。
CS9043エラーの発生原因
エラー内容と背景
CS9043エラーは、ref returningプロパティとrequired 修飾子を同時に利用した際に発生します。
コンパイラは、オブジェクト初期化時に必須となるプロパティが、setterを持たないref returningプロパティである場合、オブジェクト初期化子を使用できなくなるため、このエラーを出力します。
Microsoftの公式ドキュメントでも、ref returningプロパティにはsetterがないため、requiredとして設定することができないと明記されています。
オブジェクト初期化時の要件と問題点
オブジェクト初期化子を使用する場合、プロパティの初期化が必須となることがrequired 修飾子で指定されます。
しかし、ref returningプロパティは読み取り専用であり、setアクセサーが存在しません。
そのため、読み取り専用プロパティに対してrequired修飾子を設定すると、オブジェクト初期化の際に値が設定されることが保証できず、結果としてCS9043エラーが発生するという問題点があります。
ref returning プロパティの特徴
動作仕様と制約
ref returningプロパティは、内部の変数の参照を返す仕組みです。
この仕組みにより、メモリ上の実体を直接操作できる利点がありますが、値の変更や安全な初期化が通常のプロパティと異なるため、設計時に注意が必要です。
また、getterのみの実装が一般的であり、setアクセサーのサポートはされていません。
この制限は、プロパティが参照を返すことに起因するものです。
setter不在による影響
setアクセサーが存在しないため、ref returningプロパティは値の代入ができません。
この特徴は、参照を直接返すための設計上の制約に起因しています。
つまり、プロパティ値の初期化や更新が外部から行えないため、オブジェクト初期化子でプロパティに値を設定しようとするとエラーが発生します。
これにより、設計方針としてオブジェクト初期化子の利用が制限されるケースがあります。
required 修飾子の仕様
利用目的と機能
required 修飾子は、オブジェクト初期化時に特定のプロパティが必ず初期化されることを保証するために導入されました。
これにより、オブジェクトが不完全な状態で生成されるリスクを軽減し、コードの安全性を向上させることができます。
ユーザーが意図しない値の欠落を防ぐため、クラス設計時に必要なプロパティに対してrequired修飾子を付与することで、初期化時のエラーを未然に防止することができるのです。
プロパティ初期化との組み合わせ制限
required 修飾子を付加したプロパティは、オブジェクト初期化子を使って値が設定される必要があります。
しかし、setterのないref returningプロパティは、外部から値を代入できないため、required 修飾子と組み合わせることができません。
これが、CS9043エラーの発生原因となり、該当するプロパティを初期化できない状態を生み出します。
コード例による現象の検証
エラーが発生するコードの構造
エラーが発生するコードは、ref returningプロパティにrequired修飾子を付ける構造になっています。
具体的には、返却される値が読み取り専用であり、setアクセサーが欠如しているため、オブジェクト初期化子での値設定ができません。
以下のサンプルコードは、エラーが発生する例を示しています。
// CS9043.cs
using System;
class SampleClass
{
private int internalValue;
// required と ref returning プロパティの組み合わせによりCS9043エラーが発生する例
public required ref readonly int Number => ref internalValue;
}
class Program
{
static void Main(string[] args)
{
// オブジェクト初期化子でNumberプロパティを設定しようとするとエラーとなる
var sample = new SampleClass() { /* Number = 10 <- ここでエラー CS9043 が発生 */ };
Console.WriteLine("Sample program started.");
}
}
エラーメッセージのポイント
コンパイラが出力するエラーメッセージは、「ref returningプロパティを必須にすることはできません」という内容です。
このメッセージは、プロパティがsetアクセサーを持たないことを明確に示しており、オブジェクト初期化子で値が設定できない点を指摘しています。
エラーの原因箇所を特定する上で、プロパティの宣言部分が注目すべきポイントとなります。
エラー解決方法の詳細
値渡しプロパティへのリファクタリング
コード変更の流れ
CS9043エラーを解決するためには、ref returningプロパティを値渡しプロパティに変更する必要があります。
具体的には、ref修飾子を削除し、通常のプロパティとして実装し直します。
以下のサンプルコードは、エラー解決前と解決後のコード変更の流れを示しています。
// エラー発生前のコード
using System;
class SampleClassBefore
{
private int internalValue;
// エラー:ref returning と required の組み合わせ
public required ref readonly int Number => ref internalValue;
}
class ProgramBefore
{
static void Main(string[] args)
{
// こちらのコードはコンパイルエラーを引き起こします。
// var sample = new SampleClassBefore() { Number = 10 };
Console.WriteLine("コンパイルエラーが発生するコードです。");
}
}
// エラー解決後のコード
using System;
class SampleClassAfter
{
private int internalValue;
// エラー解決: 通常の値渡しプロパティとして再実装
public required int Number
{
get
{
return internalValue;
}
set
{
internalValue = value;
}
}
}
class ProgramAfter
{
static void Main(string[] args)
{
// オブジェクト初期化子を使用してプロパティに値を設定可能です
var sample = new SampleClassAfter() { Number = 10 };
Console.WriteLine($"Number: {sample.Number}");
}
}
Number: 10
変更後の動作確認方法
変更後のコードが正しく動作するかどうかは、実際にコンパイルしてオブジェクト初期化子でNumber
プロパティに値を設定し、出力結果が期待通りになっているかを確認することで検証できます。
具体的には、コンパイルエラーが解消され、Main
関数内でNumber
の値が表示されることをもって成功と判断できます。
エラーメッセージが出ず、実行時に
まとめ
本記事では、ref returningプロパティとrequired修飾子の組み合わせによって発生するCS9043エラーについて解説しました。
エラーの発生要因や、オブジェクト初期化時のプロパティ設定の仕組み、ref returningプロパティの仕様と制限点が理解できます。
また、エラー解決のために、値渡しプロパティへのリファクタリング方法と動作確認の手順が具体的なコード例を通して学べます。