7

Jeffrey Richter のCLR を C# 第 4 版(Microsoft Press) で読んでいるときに、著者はある時点で、Object.Equals現在 ID の等価性をチェックしているが、Microsoftは次のような方法を実装すべきだったと述べています。

public class Object {
    public virtual Boolean Equals(Object obj) {
        // The given object to compare to can't be null
        if (obj == null) return false;

        // If objects are different types, they can't be equal.
        if (this.GetType() != obj.GetType()) return false;

        // If objects are same type, return true if all of their fields match
        // Because System.Object defines no fields, the fields match
        return true;
    }
}

これは非常に奇妙に思えます。同じタイプの null 以外のオブジェクトはすべてデフォルトで等しいのでしょうか? したがって、オーバーライドされない限り、型のすべてのインスタンスは等しく (たとえば、すべてのロック オブジェクトが等しい)、同じハッシュ コードを返します。==そして、 onObjectがまだ参照の等価性をチェックしていると仮定すると、これは(a == b) != a.Equals(b)どちらも奇妙になることを意味します。

オーバーライドされない限り、すべてを等しくするよりも、まったく同じもの (同一性) であれば等しいという考えの方が良いと思います。しかし、これはマイクロソフトが発行した有名な本の第 4 版であるため、このアイデアには何らかのメリットがあるはずです。私はテキストの残りの部分を読みましたが、疑問に思わずにはいられませんでした:なぜ著者はこれを提案したのでしょうか? ここで何が欠けていますか?現在の Object.Equals 実装に対する Richter の実装の大きな利点は何ですか?

4

4 に答える 4

5

現在のデフォルトでEquals()は、いわゆる浅い比較 (または参照比較) が行われ、参照が異なるかどうかはそれ以上チェックされません。

これは、基本的な実装には完全に受け入れられると思います。私はそれが間違っているとか不完全だとは決して思いません。

あなたが引用したリヒターの例1も、ベース System.Object に対して完全に正当です。彼の実装の問題は、間違いなくabstract 2と宣言する必要があることです-彼の方法では、Equals()オーバーライドしないと、派生オブジェクトの信頼性が低くなります(Equals()深い比較を行う必要があるため)。すべての派生オブジェクトでこのメソッドをオーバーライドしなければならないのは大変な作業になるため、Microsoft の方法がデフォルトとして優れています。したがって、本質的にはあなたは正しいです.Richterの例は奇妙です-デフォルトで等しくないことを逆にするよりも良いです(デフォルトをデフォルトにするtrueと、人々がそれをオーバーライドするのを忘れた場合、かなり興味深い動作になります)。

(簡単に参照できるように、本で公開されているデフォルトの実装を次に示します)

ここに画像の説明を入力



1: リヒターは自分のことをよく知っている頭のいい男で、私は彼の言うことに異議を唱えたりはしません。MS のエンジニアは、間違いを犯して後で修正するだけの柔軟性を持っていなかったことを知っており、多くのことについて長く懸命に考えなければならなかったことを理解する必要があります。彼らがどんなに正しかったとしても、人々は必ず後でそれを推測し、別の意見を提供します. これは、オリジナルが間違っているとか、代替案が間違っているという意味ではなく、単に代替案があったということです。

2: もちろん、これは基本的な実装がないことを意味します。信頼性が低いため、これは良いことです。

于 2013-02-06T02:35:03.567 に答える
3

Jeffery Richter は、アイデンティティの平等よりも価値の平等について語っています。

具体的には、次のように尋ねます。

オーバーライドされない限り、型のすべてのインスタンスは等しいですか?

答えはYesですが... のように、Yes, But(ほとんど) 常にオーバーライドされることになっています。

したがって、ほとんどのクラスでは、属性ごとの比較を行って同等性を判断するようにオーバーライドする必要があります。真に ID ベースの他のクラス (ロックなど) については、現在使用されているのと同じ手法を使用するようにオーバーライドする必要があります。

ただし、重要なのは、ほとんどすべての場合にオーバーライドする必要があるということです。これだけでも十分に困難で、ぎこちなく、間違いが発生しやすいため、Microsoft がこのアプローチを使用しなかった可能性があります。


同一性平等に対する価値平等の利点は何ですか? 2 つの異なるオブジェクトが同じ値/コンテンツを持っている場合、Dictionary オブジェクトの Keys のような場合に、比較のために「等しい」と見なすことができます。

または、実際にはオブジェクトである .Net の文字列の問題を考えてみてください。ただし、より高いレベル (特に VB.net) では値のように扱われます。これは、2 つの文字列が等しいかどうかを比較する場合に問題を引き起こします。99% の場合、それらが異なるオブジェクトインスタンスであるかどうかは気にせず、同じテキストが含まれているかどうかだけを気にするからです。したがって、実際にはオブジェクトであっても、.Net は文字列比較が実際にどのように機能するかを確認する必要があります。

于 2013-02-06T02:36:06.573 に答える
1

任意のタイプの識別可能に異なるすべてのオブジェクトのリストを作成するように求められ、オブジェクトが何であるか、またはそれらが何に使用されるかについての指示が与えられていない場合、2 つの参照を使用する必要があるかどうかをテストする唯一の普遍的に適用可能な手段は、識別可能に異なるオブジェクトを指していると見なされるのはObject.Equals(Object)です。2 つの参照Xとは、現在 を指している 1 つ以上の参照を変更して代わりに指すように変更すると、プログラムの動作が変更される可能性が高いY場合、識別可能なように異なると見なす必要があります。XY

たとえば、両方の 2 つのインスタンスにWar and Peacestringのテキスト全体が含まれており、句読点とフォーマットが同じである場合、最初の参照の一部またはすべてを 2 番目の参照に置き換えるか、またはその逆で、プログラムにほとんどまたはまったく影響を与えない可能性があります。同じインスタンスを指す 2 つの参照間の比較は、同一の文字を含む異なる文字列を指す 2 つの参照よりもはるかに迅速に同一のテキストを保持することが判明する可能性があるという事実を超えて実行します。

ほとんどの場合、不変データを保持するために存在するオブジェクトは、それらが保持するデータが同一で​​ある場合、同一であると見なされます。変更可能なデータを保持するために存在するオブジェクト、または ID トークンとして機能するために存在するオブジェクトは、通常、互いに別個のものと見なされるべきです。完全に等価ではない等価オブジェクト (大文字と小文字を区別しない文字列比較子など) と見なすカスタムEqualityComparerを定義できる場合、および厳密な等価よりも広い等価の定義を必要とするコードを考えると、一般に、それがどの型であるかを知っている必要があります。同等の定義が適切である場合、一般的には、Object.Equals置換可能になるように設計されていない限り (文字列など)、レポート オブジェクトを異なるものとして保持することをお勧めします。

実世界で例えると、車両識別番号が書かれた 2 枚の紙が与えられ、最初の紙で識別された車が 2 番目の紙で識別された車と同じかどうか尋ねられたとします。 . 2 枚の紙片の VIN が同じ場合、1 枚目で識別された車は 2 枚目で識別された車と同じであることは明らかです。ただし、車が複数の VIN を持っているという奇妙な可能性を除外して、それらが異なる VIN を持っている場合、それらは異なる車を識別します。車のメーカーとモデル、オプション パッケージ、塗装スキームなどが同じであっても、それらは異なる車であることに変わりはありません。一方を購入した人は、代わりにもう一方を勝手に使い始める権利はありません。2 台の車が現在同じオプション パッケージなどを持っているかどうかを知ることが役立つ場合があります。

于 2013-02-12T20:34:02.357 に答える
0

推測:の現在の動作はObject.Equals、ほとんどの人が「等しい」と見なすものではありません。

このメソッドが存在する主な(唯一の?)理由は、「==」実装のふりをしてコレクション内のアイテムを検索できるようにすることです。したがって、ほとんどの実際のケースでは、この実装は予期しない動作をし(特定のインスタンスがすでにコレクションにあるかどうかを確認したい場合を除く)、カスタム比較関数を提供する必要があります...

技術的な理由から、オブジェクトのメソッドである可能性があります。つまり、配列/辞書の場合、「検索」機能を有効にするためにオブジェクトで何かをチェックする代わりに、すべてのオブジェクトがEqual/を持っていると想定する方が速い場合があります。GetHash

おそらく、それはObjectにあるべきではなく、代わりに、何らかの形式のIComparableインターフェースを実装するためにコレクションに格納できるクラスを必要とするだけです。

于 2013-02-06T02:45:32.200 に答える