構造体型の格納場所 (変数、パラメーター、配列要素、またはフィールド) は、すべてのパブリック フィールドとプライベート フィールドの値を保持します。通常は連結されますが、パディングが含まれる場合もあります。クラス型の格納場所には、ヒープ オブジェクト (4 ~ 8 バイト) への (null の可能性がある) 参照が保持されます。ヒープ オブジェクトは、8 ~ 16 バイトのオーバーヘッドに加えて、オブジェクトとその先祖が保持するすべてのパブリック フィールド、保護フィールド、およびプライベート フィールドの内容を保持します。
保存するものが固定サイズの値のバンドルである場合は、ほとんどの場合、公開されたフィールドを持つ構造体を使用する必要があります。構造体は不変でなければならないという考えは、C# コンパイラが次のようなコードを使用していた時代にまでさかのぼります。
読み取り専用 Point Pt = new Point(3,4);
void Yippie() { Pt.X += 5; }
Yippie
新しい一時的なインスタンスを作成し、それにPoint
コピーして、その一時的なインスタンスでプロパティ セッターをPt
呼び出し、破棄します。X
このようなナンセンスを防ぐ適切な方法は、コンパイラに「申し訳ありませんが、読み取り専用の構造体変数でプロパティ セッターを呼び出すことはできません」と言わせるのではなく、読み取り専用のプロパティを持つように構造を定義することだと誰かが考えました。セッターなし。行うべき適切なことは、変化しようとしている構造体のメソッドまたはプロパティがthis
その宣言でそのように示すことを要求し、読み取り専用構造体でのそのようなメソッドまたはプロパティの使用を禁止することでした。
プロパティで構造体フィールドをラップするとパフォーマンスが低下するため、構造体の不変条件を強制する必要がある場合を除いて、これはお勧めしません。また、 structsreadonly
の宣言を避けることをお勧めします。宣言された構造体は、フィールドがアクセスされるたびに完全にコピーされるためです。
ちなみに、変更可能なクラスの型について注意すべき重要な点: 変更可能なクラス オブジェクトの状態には、そのフィールドの内容だけでなく、それに存在するすべての参照のセットも含まれます。場合によっては、これが役立つことがあります。多くの場合、重大な問題を回避する唯一の方法は、変更可能なオブジェクトへの参照を保持するエンティティがそのような参照を共有しないようにすることです。何かをクラス型にすると、参照が無差別に渡されるのを防ぐために余分な作業が必要になる場合、それは問題の型が構造体であるべきであるという良い兆候です。