自動プロパティと構造は混在しませんか?
-
05-07-2019 - |
質問
この投稿に答えながらいくつかの小さな構造物を蹴ると、思いがけず次のことがわかりました。
intフィールドを使用した次の構造は完全に正当です:
struct MyStruct
{
public MyStruct ( int size )
{
this.Size = size; // <-- Legal assignment.
}
public int Size;
}
ただし、自動プロパティを使用した次の構造はコンパイルされません。
struct MyStruct
{
public MyStruct ( int size )
{
this.Size = size; // <-- Compile-Time Error!
}
public int Size{get; set;}
}
返されるエラーは、「すべてのフィールドが割り当てられるまで「this」オブジェクトを使用できません」です。これは構造体の標準的な手順であることを知っています。プロパティのバッキングフィールドは、構造体のコンストラクタ内から直接(プロパティのsetアクセサを介してではなく)割り当てる必要があります。
解決策は、明示的なバッキングフィールドを使用することです。
struct MyStruct
{
public MyStruct(int size)
{
_size = size;
}
private int _size;
public int Size
{
get { return _size; }
set { _size = value; }
}
}
(VB.NETではすべてのフィールドが最初に作成されたときに自動的に0 / null / falseに初期化されるため、VB.NETにはこの問題はありません。)
C#の構造体で自動プロパティを使用する場合、これは不幸な制限のようです。概念的に考えると、少なくとも自動プロパティの場合、プロパティセットアクセサを構造体のコンストラクタ内で呼び出すことを許可する例外があるのに、これが合理的な場所ではないかと思いましたか?
これは小さな問題であり、ほとんどエッジケースですが、他の人がこれについてどう思っているのか疑問に思っていました...
解決
C#6以降:これは問題ではなくなりました
Becore C#6、これを機能させるにはデフォルトのコンストラクターを呼び出す必要があります:
public MyStruct(int size) : this()
{
Size = size;
}
ここでの大きな問題は、可変構造体があることです。これは良い考えではありません決して。私はそれをするでしょう:
public int Size { get; private set; }
技術的に不変ではないが、十分に近い。
C#の最近のバージョンでは、これを改善できます:
public int Size { get; }
これは、コンストラクターでのみに割り当てることができます。
他のヒント
これを修正するには、最初にデフォルトのコンストラクターを呼び出します:
struct MyStruct
{
public MyStruct(int size) : this()
{
this.Size = size; // <-- now works
}
public int Size { get; set; }
}
この問題のもう1つのわかりにくい回避策は、Tuple クラスにあるものです。 > Managed Extensibility Framework ( Krzysztof Ko&#378; mic ):
public struct TempTuple<TFirst, TSecond>
{
public TempTuple(TFirst first, TSecond second)
{
this = new TempTuple<TFirst, TSecond>(); // Kung fu!
this.First = first;
this.Second = second;
}
public TFirst First { get; private set; }
public TSecond Second { get; private set; }
(Codeplexの完全なソースコード: Tuple.cs )
CS0188 のドキュメントが更新されたことにも注意してください。追加:
しようとしたときにこのエラーが表示される場合 構造体のプロパティを初期化する コンストラクタ、解決策は変更することです 指定するコンストラクターパラメーター 代わりにバッキングフィールド プロパティ自体。 自動実装 プロパティは 構造体にはバッキングがないため フィールドであるため、 から何らかの方法で初期化 コンストラクタ。
だから、公式のガイダンスでは、この問題に遭遇したときに構造体で古いスタイルのプロパティを使用することを意味します。おそらく、他の2つの選択肢のいずれかよりもわかりにくく(読みやすい)でしょう遠い。