オGetHashCodeのための可変オブジェクト?
-
22-08-2019 - |
質問
っくりとした約10種類の質問がどのようにオーバーライド GetHashCode
がまだ分からないかを取得します。ほとんどの実装の GetHashCode
に基づくハッシュコードの分野においてオブジェクトが引用される値 GetHashCode
などが変更有効期間のオブジェクトです。どのような作業の場合は分野で基づいて変更可能な?ものになっているのでしょうか?いい辞書をルックアップなどに基づく参考平等ではなくてオーバーライド Equals
?
私は主にオ Equals
のためのユニット試験は私の直列化コードを前提にしてい直列化さとdeserializing(XMLっ殺しの参考平等で確認して欲しいですが正しい値を進めていきます。は、この実践をオーバーライド Equals
かるでしょうか?基本的にはほとんどのコードを実行したいを参考平等とは必ず使う ==
見たいな方法が良いと思いますをオーバー。ばん新しい方法 ValueEquals
たものではなくよりも優 Equals
?私は使用することができるものとし、枠組みは常に使用 ==
ない Equals
比較ものとしていかないといけないと思いました安全なオーバーライド Equals
でも私のようにその目的のためにしたい場合についての第2回の定義等は違うから ==
オペレーターから読みつその他のご質問もいるようではありません。
編集:
い私の意図が不鮮明となり、うち99%の時間にしたいの平野は旧基準の平等、デフォルトの動作は、驚くことで生きています。のための非常に稀にしたい値が等して大事にしていきたいと思いを明示的に要求値の平等を .Equals
の代わりに ==
.
私はこのコンパイラを推奨しいオーバーライド GetHashCode
などをすることで、この問題になってしまうのです。されるようになったと連絡が相反する目標 GetHashCode
を適用すると、変更可能なオブジェクトがされている:
- の場合
a.Equals(b)
そのa.GetHashCode()
すべ== b.GetHashCode()
. - の値
a.GetHashCode()
は変更できませんの生涯のa
.
このように自然に矛盾が変更可能なオブジェクトでの状態がオブジェクトの変化、価値の .Equals()
変更が GetHashCode
変わりに合わせ変更 .Equals()
, ものの、 GetHashCode
べき変わりません。
なぜがなされているとは聞いているこの矛盾?これらの勧告ではありませんへ変更可能なオブジェクト?しょう想定があろう授業のない構造体.
分解能:
私はマーキングJaredParとして受け入れが主にコメントします。にいることに全てが充実するために、目標を回避する個性豊かな行動のエッジケースであり、オーバーライド Equals
や GetHashCode
に基づく不変の分野、または実施 IEquatable
.このようなも低下の有用性をオーバー Equals
参考種類とらんどろ風mikiモデルを作ってみないかという見方が参照型の通常のない不変の分野なんで保存され、リレーショナルデータベースを特定し、主要な鍵となります。
解決
はその仕事をしてどのようにそれはに基づいているフィールドは変更可能ですか?
これは、ハッシュコードは、オブジェクトの変更として変化するという意味ではありません。それはあなたが読んで記事に記載されている理由のすべてのための問題です。残念ながら、これは通常、唯一のコーナーケースに表示問題のタイプです。だから、開発者は悪い行動に逃げる傾向がある。
また、私は、辞書検索をしたいです場合などは、私のオーバーライドされた対等ではない参照の等価に基づいべきでしょうか?
限り、あなたは、これが問題になることはありませんIEquatable<T>
ようなインターフェイスを実装して。ほとんどの辞書の実装はObject.ReferenceEquals上IEquatable<T>
を使用する方法で、等値比較子を選択します。でもIEquatable<T>
なしで、ほとんどは、あなたの実装になりますはObject.equals()を呼び出すにデフォルト設定されます。
基本的に実行されるコードのほとんどで、私は参照の等価をしたいと私はいつも==使用して、私はそれをオーバーライドしていないよ。
あなたのオブジェクトが値平等に振る舞うことが予想される場合は、あなたは==オーバーライドしなければならないと!=すべての比較のための値の平等を強制します。彼らは実際に参照の等価をしたい場合、ユーザーはまだObject.ReferenceEqualsを使用することができます。
私は、フレームワークは、常に物事
を比較するために等しい==使用しないことを前提とするために使用しました BCL用途が時間をかけて少し変わったものは。今平等を使用し、ほとんどの場合はIEqualityComparer<T>
インスタンスを取ると平等のためにそれを使用します。一つは、彼らがものを見つけるためにEqualityComparer<T>.Default
を使用する指定されていない場合には。最悪のケースでは、これは
他のヒント
、あなたが実際にそれを使用することはできませんよう、GetHashCodeメソッドをオーバーライドに多くのポイントがありません。バケット内の各項目を配置するDictionary
とHashSet
コレクションで、たとえば使われています。それは、コレクション内のキーとして使用している間、あなたがオブジェクトを変更した場合、ハッシュコードはもはやオブジェクトが入っているバケツに一致し、そのコレクションが正常に動作しない、あなたは、オブジェクトを再び見つけることはありませんがあります。
あなたは、ルックアップは、クラスのGetHashCode
またはEquals
メソッドを使用しない場合、あなたは常にあなたがIEqualityComparer
を作成するときに代わりに使用する独自のDictionary
実装を提供することができます。
Equals
メソッドは、値の平等を対象とし、それはそのように実装するのは間違っていないのですされます。
うわー、それは実際には1つ:-)でいくつかの質問です。他の後にそう1:
GetHashCodeメソッドの値は、オブジェクトの生存期間の経過とともに変化することはありませんことを引用されています。それはに基づいているフィールドが変更可能であればどのようにその仕事をしますか?
この一般的なアドバイスは、あなたがハッシュテーブル/辞書などでキーとして、あなたのオブジェクトを使用したい場合のためのものです。彼らは保存&キーを取得する方法を決定するためにそれを使用しているため、ハッシュテーブルは、通常は、変更しないハッシュを必要としています。ハッシュが変更された場合、ハッシュテーブルは、おそらく、もはやあなたのオブジェクトを検索しません。
Javaのの地図のインターフェイスのドキュメントを引用するには
注:可変オブジェクトがマップのキーとして使用されている場合には、十分な注意を払わなければなりません。オブジェクトの値は、オブジェクトがマップのキーである比較に等しく影響するように変更された場合、マップの動作が指定されていない。
一般的には、ハッシュテーブルのキーとして可変オブジェクトののいずれかののようなものを使用することが悪い考えです:それは重要な変更された場合、それがハッシュテーブルに追加されていた後にどうするかさえはっきりしていません。ハッシュテーブルは、古いキーを経由して、または新しいキーを経由して、あるいはその両方を経由して格納されているオブジェクトを返す必要がありますか?
だから、本当のアドバイスです:のみキーとして不変オブジェクトを使用し、そのハッシュコードは、(オブジェクトが不変であれば、通常は自動的に行われている)のいずれかに変更はありませんことを確認してください。
。また、私は参照の等価ではない私のオーバーライドされた対等に基づくように辞書検索などをしたいですか何かの?
さて、そのように動作します辞書の実装を見つけます。しかし、標準ライブラリの辞書には、ハッシュコードを使用&等しく、それを変更する方法はありません。
私は主にオーバーライドが、私は(私の場合にはXMLに)シリアライズおよびデシリアライズを前提と私のシリアル化コードをテストユニットを容易にするために等しいですので、私は、少なくとも、それは価値の平等で正しいです確認する参照の等価を殺します。この場合のequalsをオーバーライドするには、この悪い習慣はありますか?
いいえ、私はそれが完全に受け入れ見つけるだろう。彼らは変更可能だとしてしかし、あなたは、辞書/ハッシュテーブルにあるキーのようなオブジェクトを使用しないでください。上記を参照してください。
ここでの基本的なトピックは、最高の一意のオブジェクトを特定する方法です。あなたは、参照整合性は、その過程で失われているために重要であるシリアライズ/デシリアライズ言及します。
短い答えは、オブジェクトを一意にそうするために使用することができ不変フィールドの最小セットで識別されなければならないということです。これらは、GetHashCodeメソッドをoverrideingと等しいときに使用するフィールドです。
テストするためには、これらは型自体にではなく、テストスイートのユーティリティメソッドとして定義されていない通常、何が必要アサーションを定義するために完全に合理的です。たぶんTestSuite.AssertEquals(MyClassの、MyClassの)?
GetHashCodeメソッドとequalsが協力すべきであることに注意してください。それらが等しい場合GetHashCodeメソッドは、2つのオブジェクトに同じ値を返す必要があります。そして2つのオブジェクトが同じハッシュコードを持っている場合にだけ等号はtrueを返す必要があります。 (これは、2つのオブジェクトは等しくなくてもよいことは可能だが、同じハッシュコードを返すことができることに留意されたいです)。このトピックは、ヘッドオン、わずかの距離グーグル取り組むWebページがたくさんあります。
私はそれに比べてのnoobされ、C#のことは知らないが、あなたが等号をオーバーライドする場合は、Javaで、()あなたも彼ら(またはその逆)との間の契約を維持するためのhashCode()をオーバーライドする必要があります。.. 。とJavaは、同じキャッチ22を有しています。基本的には不変のフィールドを使用して強制的に...しかし、これは唯一のハッシュ・キーとして使用されているクラスのための問題であり、そしてJavaは、すべてのハッシュベースのコレクションのための代替の実装を持っている...多分早くはないが、彼らはeffecitely行いますそれだけだ...あなたがキーとして可変オブジェクトを使用できるようにする(通常は)「貧しいデザイン」としてアップ眉をひそめています。
そして、私はアダムが若者だったので、それは回避されています...この根本的な問題は、時代を超越していることを指摘して衝動を感じます。
私は私より年上ですFortranコードで働いてきたユーザ名が;-)女の子が結婚したときのように(変更、または離婚したとき...壊れた(私は36だ)そこでエンジニアリングは、あります採用されたソリューションは:GetHashCodeメソッド「メソッド」は、以前に計算のhashCodeを覚えているのhashCode(すなわち仮想isDirtyマーカー)を再計算し、keyfieldsが変更された場合、それはnullを返します。これは、(別のGetPreviousHashCodeを呼び出すことで)「汚い」ユーザーを削除するキャッシュを起こし、その後、キャッシュは、ユーザーがデータベースから再読み込みさせ、nullを返します。面白くてやりがいのあるハック。私はそう自分自身を言うのない場合でも、 - )
私はトレードオフのでしょうOのための可変性(コーナーケースでのみ望ましい)(1)アクセス(すべての場合に望ましいです)。エンジニアリングへようこそ。通知妥協の土地ます。
乾杯。キースます。