不変性がどのように定義されているのだろうか?値がパブリックとして公開されていないため、変更できない場合は、それで十分ですか?
型の顧客ではなく、型内で値を変更できますか?
それとも、コンストラクター内でのみ設定できますか? もしそうなら、二重初期化の場合 (this
構造体でキーワードを使用するなど) は、不変型に対してまだ問題ありませんか?
型が 100% 不変であることをどのように保証できますか?
不変性がどのように定義されているのだろうか?値がパブリックとして公開されていないため、変更できない場合は、それで十分ですか?
型の顧客ではなく、型内で値を変更できますか?
それとも、コンストラクター内でのみ設定できますか? もしそうなら、二重初期化の場合 (this
構造体でキーワードを使用するなど) は、不変型に対してまだ問題ありませんか?
型が 100% 不変であることをどのように保証できますか?
値がパブリックとして公開されていないため、変更できない場合は、それで十分ですか?
いいえ、読み取りアクセスが必要なためです。
型の顧客ではなく、型内で値を変更できますか?
いいえ、それはまだ突然変異だからです。
それとも、コンストラクター内でのみ設定できますか?
ディンディンディン!不変型には、多くの場合、新しいインスタンスを構築して返すメソッドがありinternal
、それらのメソッドで使用するために特別にマークされた追加のコンストラクターがあることが多いという追加のポイントがあります。
型が 100% 不変であることをどのように保証できますか?
.Net では、リフレクションを使用してプライベート メンバーを変更 (変更) できるため、このような保証を得るのは難しいです。
以前の投稿者は、コンストラクターでフィールドに値を代入してから手を離す必要があると既に述べています。しかし、それは言うは易く行うは難しです。不変オブジェクトが type のプロパティを公開しているとしましょうList<string>
。そのリストは変更できますか? そうでない場合、どのように制御しますか?
Eric Lippert は、C# の不変性に関する一連の投稿を彼のブログに書いています。興味深いかもしれません。最初の部分は、こちら にあります。
これらすべての回答で見逃されている可能性があると思うことの 1 つは、オブジェクトの内部状態が変化しても、それらの内部変化が「クライアント」コードに表示されない限り、オブジェクトは不変であると見なすことができると思うことです。
たとえば、System.String
クラスは不変ですが、インスタンスのハッシュ コードをキャッシュすることは許可されているので、ハッシュは への最初の呼び出しでのみ計算されGetHashCode()
ます。私の知る限り、System.String
クラスはこれを行いませんが、不変と見なされる可能性があることに注意してください。もちろん、これらの変更はいずれも、スレッドセーフな方法で処理する必要があります (変更の観察不可能な側面に合わせて)。
正直なところ、この種の「目に見えない可変性」が必要な理由や必要な理由はあまり思いつきません。
ウィキペディアからの不変性の定義は次のとおりです(リンク)
「オブジェクト指向および関数型プログラミングでは、不変オブジェクトは、作成後に状態を変更できないオブジェクトです。」
基本的に、オブジェクトが作成されると、そのプロパティを変更することはできません。例は String クラスです。String オブジェクトが作成されると、変更することはできません。それに対して行われた操作は、実際には新しい String オブジェクトを作成します。
そこにはたくさんの質問があります。私はそれらのそれぞれに個別に答えようとします:
「不変性はどのように定義されているのだろうか?」-ウィキペディアのページから直接(および完全に正確/簡潔な定義)
不変オブジェクトは、作成後に状態を変更できないオブジェクトです
「値が公開されていないため、変更できない場合は、それで十分ですか?」- そうではありません。いかなる方法でも変更できないため、メソッド/関数がオブジェクトの状態を変更しないようにし、操作を実行する場合は常に新しいインスタンスを返す必要があります。
「型の顧客ではなく、型の内部で値を変更できますか?」- 技術的には、型の内部またはコンシューマーによって変更することはできません。System.String
実際には、理論上ではありませんが、ほとんどすべての実用的な目的で変更可能と見なすことができる (問題の参照型)などの型が存在します。
「または、コンストラクター内でのみ設定できますか?」- はい、理論的には、状態 (変数) を設定できる唯一の場所です。
「もしそうなら、二重初期化の場合 (構造体で this キーワードを使用するなど) は、不変型に対してまだ問題ありませんか?」- はい、それでもまったく問題ありません。これはすべて初期化 (作成) プロセスの一部であり、完了するまでインスタンスは返されないためです。
「型が 100% 不変であることをどのように保証できますか?」- 次の条件は、それを保証する必要があります。(抜けていたら誰か指摘してください。)
private
(protected
派生クラスは状態を変更できるため、受け入れられません)。注: 派生型は新しい変数を定義できるため、派生型の不変性を保証することはできません。sealed
これは、派生クラスがコード内のどこでもベースの不変型であると見なされないように、不変であることを確認したくない型をマークする理由です。
それが役立つことを願っています。
残念ながら、c#/ vb.netには不変のキーワードはありませんが、議論されていますが、autopropertiesがなく、すべてのフィールドが読み取り専用(読み取り専用フィールドはコンストラクターでのみ割り当てられる)modfierで宣言され、すべてのフィールドが宣言されている場合自己不変性を保証する不変型。
不変オブジェクトとは、もっともらしいコード実行シーケンスによって監視可能な状態が決して変更されないオブジェクトです。不変型とは、外部の世界に公開されるすべてのインスタンスが不変であることを保証する型です (この要件は、オブジェクトの状態がそのコンストラクターでのみ設定される必要があるとよく言われます。これは、また、構築中に外部メソッドを呼び出すオブジェクトの場合も十分ではありません)。
ただし、他の回答が無視している点は、オブジェクトの状態の定義です。Foo
がクラスの場合、 の状態は、そこに含まれるList<Foo>
一連のオブジェクト IDで構成されます。特定のインスタンスへの唯一の参照が、List<Foo>
そのシーケンスを変更せず、変更する可能性のあるコードに公開しないコードによって保持されている場合、そのインスタンスは、Foo
その中で参照されているオブジェクトが変更可能かどうかに関係なく、不変になります。不変。
例えるなら、自動車の VIN (Vehicle Identification Numbers) のリストが改ざん防止用紙に印刷されている場合、自動車はそうではありませんが、リスト自体は不変です。リストに今日赤い車が 10 台含まれていても、明日には青い車が 10 台含まれる可能性があります。ただし、それでも同じ 10 台の車になります。
不変性とは、コンストラクターですべてを設定し、後でオブジェクトの有効期間中に変更できない場合であることを学びました。
不変性の定義はGoogleにあります。
例:
不変 - 文字通り、変更できません。
www.filosofia.net/materiales/rec/glosaen.htm
イミュータブルなデータ構造に関して言えば、典型的な定義は write-once-read-many です。つまり、あなたが言うように、一度作成すると変更することはできません。
若干グレーゾーンに入るケースもあります。たとえば、.NET 文字列は変更できないため不変と見なされますが、StringBuilder は String オブジェクトを内部的に変更します。
不変は本質的に、それ自身のコード内から強制的に final になるクラスです。それがそこにあると、何も変更できません。私の知る限り、物事はコンストラクターで設定され、それで終わりです。そうでなければ、何かがどのように不変になるのかわかりません。