私は、その値を失うフィールドを持つStructを持っています。私はフィールドを静的に宣言でき、それが問題を解決します。私はまた、構造体をクラスに変更するだけで(何も変えずに)問題を解決することもできます。なぜ私はこのことが不思議だったのですか?同じクラスのフィールドにない場合、構造体のフィールドがその値を失うのはなぜですか?
答えて
構造体は値渡しされます。つまり、構造体を渡すと、その値のコピーが渡されます。したがって、値のコピーを取り、それを変更すると、オリジナルは変更されません。元のコピーではなくコピーを変更しました。
あなたのコードを見ることなく、私は確信することはできませんが、これは起こっていると思います。
これは、参照によって渡されたクラスでは発生しません。
これは、構造体が不変でなければならないことに言及する価値があります。つまり、いったん作成されると、値が変更されないということです。変更されたバージョンを提供する操作は新しい構造体を返します。
編集:以下のコメントでは、@ supercatは、変更可能なプロパティがより便利になることを示唆しています。しかし、構造体のプロパティセッターは奇妙な失敗を引き起こす可能性があります。構造体の仕組みを深く理解していない限り、あなたを驚かせる例があります。私にとっては、変更可能な構造体を完全に避けるだけの理由があります。
には、次のタイプを考慮してください。
struct Rectangle {
public double Left { get; set; }
}
class Shape {
public Rectangle Bounds { get; private set; }
}
[OK]を、今、このコードを想像:
myShape.Bounds.Left = 100;
おそらく、驚くほど、これは何の効果は全くを持っていません!どうして?さんが長く、まだ同等の形でコードを再書き込みしてみましょう:
var bounds = myShape.Bounds;
bounds.Left = 100;
それは値Bounds
のは、ローカル変数にコピーされ、その値がどのように変化するかここを参照する方が簡単です。しかし、どんな時点でも、元の値はShape
に更新されています。
これは、すべてのパブリック構造体を不変にするためのかなり説得力のある証拠です。あなたが何をしているのか知っていれば、変更可能な構造体は便利ですが、個人的には、私はそれらをprivateネストされたクラスとしてその形式で実際に使用します。
@supercatが指摘するように、代替が少し見苦しいです:
myShape.Bounds = new Rectangle(100, myShape.Bounds.Top,
myShape.Bounds.Width, myShape.Bounds.Height);
時にはそれがヘルパーメソッドを追加する方が便利です:
myShape.Bounds = myShape.Bounds.WithLeft(100);
'this'を変更するプロパティーセッター以外の構造体メソッドは、あなたが宣言した理由で問題があります。しかし、パブリックフィールドが公開されている古い古いデータ構造体は、コンストラクタを介した更新のみを可能にする構造体よりも優れていることがよくあります。 'MyRect.Left + = MyRect.Width;'は 'MyRect = new Rectangle(MyRect.Left + MyRect.Width、MyRect.Top、MyRect.Width、MyRect.Height);よりもはるかに明確であり、さらに高速に実行されます。変更可能な構造体はスレッドセーフな方法で使用できますが、一括置換でしか変更できない構造体は使用できないことにも注意してください。 – supercat
@supercat、私はコメントに収まらない応答で私の答えを編集しました。 –
どの現在のコンパイラが 'myShapeを受け入れるか。Bounds.X = 100'? Mineは "変数ではないため、 'G.Shape.Bounds'の戻り値を変更できません。ヘルパーメソッドに関しては、大量のコードを構造体定義に追加して、ほとんどの場合、 'tempRect = myShape.Bounds;によってより迅速かつ簡単に処理できるものを行います。 tempRect.X = 100; myShape.Bounds = tempRect; ' – supercat
構造体は値渡しされる場合には、システム呼び出し側の構造体のコピーが作成され、その内容が表示され、おそらく独自のコピーが変更されますが、呼び出し側のコピーのフィールドには影響しません。 ref
によって構造体を渡すこともできます。この場合、呼び出し先は構造体の呼び出し側のコピーで作業し、必要に応じて修正し、ref
によって同様に行うことができる関数に渡すこともできます。呼び出された関数が他の関数が利用可能な構造体の呼び出し側のコピーを作ることができる唯一の方法は、しかし、ref
ことによってそれを渡すことで、すべての機能はそれがref
によって構造体を通過したためにまで呼び出された関数が戻らないことに注意してくださいまた戻った。したがって、呼び出し元は、関数呼び出しの結果として構造体に発生する可能性のある変更は、関数呼び出しが戻るまでに発生していることが保証されます。
この動作は、クラスオブジェクトとは異なります。関数が変更可能なクラスオブジェクトを別の関数に渡す場合、関数の実行が終了した後であっても、他の関数がそのオブジェクトを即座にまたは将来の任意の時点で変更させるかどうかを知る方法がありません。変更可能なオブジェクトが外部コードによって変更されないことを確かめる唯一の方法は、オブジェクトの作成時点から放棄までのオブジェクトの唯一の所有者であることです。
セマンティクスを評価するのに慣れていない人は、まず構造体を値渡しするだけで、呼び出された関数にコピーを渡し、別の構造体格納場所を割り当てることで、構造体、値型が提供する保証は非常に便利です。 Point
が構造体であるので、一つはMyPoints[5].X += 1;
ようなステートメント(MyPoints
を想定したが配列である)ことを知ることができるMyPoints[5].X
に影響を与えますが、他のPoint
には影響しません。一つは、さらにいずれかのMyPoints
は、別の配列に置き換えられます、または何かがMyPoints[5]
に書き込むとMyPoints[5].X
が変わる唯一の方法であることを保証することができます。これとは対照的に、Point
はクラスだったとMyPoint[5]
が今まで外の世界にさらされていた、上記の文はタイプPoint
の他の保管場所のフィールド/プロパティX
に影響を与えるかどうかを知る唯一の方法は、のすべての単一の保存場所を調べることであろうそれはMyPoints[5]
と同じインスタンスを指摘している場合、コード内のどこに存在していたタイプPoint
またはObject
を確認します。特定のタイプのすべての格納場所をコードが検査する方法はないので、Point[5]
がこれまでに外部に公開されていた場合、そのような保証は不可能です。
構造体には厄介なしわが1つあります。一般的に、対象のコードに構造体への書き込みが許可されている場合は、ref
で構造体を渡すことができます。ただし、Structメソッド呼び出しおよびプロパティゲッターは、this
をref
パラメーターとして受け取りますが、上記の制限はありません。代わりに、構造体のコピーを作成し、ref
によってメソッドまたはプロパティゲッターに渡してから、構造体のコピーを作成して破棄します。メソッドまたはプロパティのゲッターがthis
の突然変異を試みるかどうかを知る方法がないため、このような場合には不平を言うことはありません。単に愚かなコードを生成するだけです。しかし、プロパティーセッター以外のものにthis
の突然変異を避けると(読み取り専用構造体ではプロパティーセッターの使用が許可されません)、問題を回避できます。
- 1. 構造体フィールドが空になるのはなぜですか?
- 2. 構造体が値型の場合、なぜそれを新しいものにできますか?
- 3. 構造体にハイブサポートオプションのフィールドを行い
- 4. 構造体からCのフィールドをプリントできない
- 5. 構造体のフィールドを含むクラスと同じテーブルに格納することは可能ですか?
- 6. 構造体にIDがない場合はどういう意味ですか?
- 7. なぜ私の構造体のフィールドを初期化できませんか?
- 8. 構造体のフィールドのリストを取得
- 9. 条件から構造体のフィールド値を返す
- 10. Android:なぜ私のEditTextフィールドがフォーカスを失うのですか?
- 11. 混乱のない構造体フィールドを表示
- 12. C++の構造体のフィールドのサイズ
- 13. Datagrid +構造体フィールドへの列のマップ
- 14. Golang変数構造体フィールド
- 15. 同じ構造体に2つの異なるサイズのセルを結合する
- 16. 同じクラスを含む構造体のベクトルを持つクラス
- 17. 構造体のオブジェクトをプログラムで作成し、構造体名とフィールド値のリストを持つときにフィールドを埋め込むことは可能ですか?
- 18. 構造体を連結する:既存のフィールドを上書きせずに構造体フィールドを更新する
- 19. 同じ構造体にないポイントコントローラーへのビュー
- 20. MATLAB構造体の各フィールドの値のサブセット
- 21. クラス内の構造体を使用する場合は、値はゼロ
- 22. なぜ構造体を別の構造体から派生できないのですか?
- 23. 関連フィールドをdbテーブルに含める場合とそうでない場合
- 24. フィールド名が同じ場合のSQL結合
- 25. 構造体がリスト内にあるときに構造体フィールドを変更
- 26. C#のデータ構造と同じように、値なし
- 27. 構造体へのバインディングが機能しないのはなぜですか?
- 28. 方法スコープパラメータ値が同じ名前のインスタンス・レベルの静的フィールドは、クラス内で宣言された場合
- 29. 数値フィールドのオーバーフロー - どのフィールドが正確ですか?エラーの場合は
- 30. MySQLフィールドの更新フィールドがフィールド=フィールド+ 1の不思議な動作の場合
コードを表示できますか? – gideon
私はあなたが何をしようとしているのか知っていると思いますが、コードを投稿してください。 –
私はこれがなぜこのような疑念を持っていますが、確認するためにはコードを提示する必要があります。 –