- ベストアンサー
c# Equalsメソッドについて
- c#初心者のためのEqualsメソッドのオーバーライド方法について
- is演算子を使わずにEqualsメソッドを実装する方法について考える
- Equalsメソッドの改善点としてtypeof演算子の利用を検討する
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
>> isではEqualsの対称性が崩れます > についてですが、「is演算子」なら対象性が崩れ、「GetType」メソッドならそれを回避できるコードは、例えばどんなものがあるでしょうか? 参考にさせてもらいたいのですがいいでしょうか? Object.EqualsのMSDNに例がありますが……。 Point.Equalsの中でGetType() != obj.GetType()としているものを,!(obj is Point)としてみてください。 ・point2D.Equals(point3Da)がtrue になる上, ・point3Db.Equals(point2D)がInvalidCastExceptionを発生させる という事態になってしまいます。 # Equalsが例外を発生させるのはContractに違反する Point3D.Equalsでさらにisによるチェックをした場合,例外は発生しませんが, ・point2D.Equals(point3Da)はtrue ・point3Db.Equals(point2D)はfalse となります。 さらに, ・point2D.Equals(point3Da)はtrue にも関わらず ・point2D.GetHashCode() != point3da.GetHashCode() という状態になってしまいます。
その他の回答 (4)
- Yune-Kichi
- ベストアンサー率74% (465/626)
Equalsでis演算子を使うことはありえません。 isではEqualsの対称性が崩れます (a.Equals(b)なのに!b.Equals(a)な可能性が出てくる)。 実装の基本は, public override bool Equals (object obj) { if (Object.ReferenceEquals(obj, null)) return false; if (Object.ReferenceEquals(this, obj)) return true; if (this.GetType() != obj.GetType()) return false; T other = (T)obj; // thisとotherの比較 } になります。 MSDN: Object.Equals メソッド (Object) (System) http://msdn.microsoft.com/ja-jp/library/bsc2ak47.aspx
お礼
回答ありがとうございます。 そういえば「GetType」メソッドなんてすっかり忘れていました。要するにこれが質問に載せたコードの「is演算子」の代わりになるということですね。 一つ追加質問ですが、いいですか? > isではEqualsの対称性が崩れます についてですが、「is演算子」なら対象性が崩れ、「GetType」メソッドならそれを回避できるコードは、例えばどんなものがあるでしょうか? 参考にさせてもらいたいのですがいいでしょうか?
- hitomura
- ベストアンサー率48% (325/664)
#1ですが、#2さんの回答を読んでちょっと前回の回答は過激だったかなと反省しております。 確かにダウンキャストを0にするためにメンテナンス不可能なくらい複雑怪奇な設計になってしまっては本末転倒ですね。 しかし、ダウンキャストは安易に使うべきではないというのは事実です。 使用するときはその前に、安易に使おうとしていないか、ダウンキャストを使わなくてもいいようにかつ明瞭なクラス設計に変更できないか、を考えてから使うべきでしょう。
お礼
回答ありがとうございます。 ダウンキャストはほどほどにと。勉強になりました。
- axsies
- ベストアンサー率64% (38/59)
基底クラスから派生クラスへの変換を「ダウンキャスト」と言います。 その逆は、「アップキャスト」と言います。 isやas演算子は、ダウンキャストのために用意されているもので、今回のケースは正当な使い方です。 一方、「is演算子なんて封印してしまえばいいのに」との回答は、 アップキャストしてポリモーフィズムすれば十分であるにも関わらず、わざわざダウンキャストしてis演算子で分岐していたため、「初心者に間違った使い方をさせるような代物ならいっそ禁止してしまえ」というちょっと過激な愚痴がつい出てしまったのでしょう。 ですが、is、as演算子はダウンキャストを行うためには必要なものです。 ダウンキャスト自体が本来避けるべきものですが、どうしても必要なケースもあります。 間違った使い方を誘発させるからと禁止しても、必要なときにバカ正直にルールに縛られて、より複雑なコードを書くのであれば、そちらの方がたちが悪いというものです。 (組織ではそれでもルールが優先されることもありますが…^^;) 要するに、道具は使いようってことです。 継承にしても演算子(orその他の言語の機能)にしても、使い方の「意図」によって良くも悪くもなりますので、適切な使い方を身につけてください。
お礼
回答ありがとうございます。 要はc#の機能を使いこなせるかどうかってことですね。使われているうちは要注意と。
- hitomura
- ベストアンサー率48% (325/664)
あなたがその回答氏からそのように言われた質問を確認しました。その上で氏の発言意図の推察込みで回答します。 この場合、is演算子を利用することは問題ありません。 氏の発言は、あなたがその質問で安易にis演算子を使用してしまっていることを嘆いてのことだと思われます。 確かに、is演算子を使えば与えられたオブジェクトが自分の想定しているクラスであることを確認できます。しかし、そのような確認が本当に必要になるのは(今回のあなたの例のような)ごく少数で、前回の質問のあなたのコード例のように通常のコードに現れることはまずありません。 というか、is演算子は無いものとしてコーディングすべき(そして、それでどうしようもなくなったときに初めてis演算子を使用すべき)です。 なぜなら、isを乱用したコードはちっともオブジェクト指向になっていないからです。あなたが補足で書いたコードを覚えていますか? あれがis演算子を乱用した結果で、ちっともオブジェクト指向していないことはお分かりのはずです。 ですから、is演算子についてのアドバイスは以下の通りです。 ・使うな。多分使用方法を間違えるから。(初心者向け) ・使うな。多分設計が間違っているから。(中級者向け) ・使うな。あなたなら使わずに何とかできるはずだ。(上級者向け) ・本当に他の手段は無いのか? ……仕方がない、使おう。(最上級者向け)
お礼
回答ありがとうございます。 なるほど。is演算子は結構きびしいのですね。
お礼
回答ありがとうございます。 追加質問に対する例が確かに書いてありましたが、気づいていませんでした。いろいろと勉強になりました。