
こんにちは、c#初心者です。
以前まで「Object」型から継承される「Equals」メソッドをオーバーライドするときは
public bool override Equals(object obj)
{
if ( obj is 現在の型 または 任意の親クラスの型 や インターフェイスの型 )
{
//判断処理
}
else
return false;
}
または、クラス限定で
public bool override Equals(object obj)
{
var temp = obj as 現在の型 または 任意の親クラスの型 や インターフェイスの型;
if ( temp != null )
{
//判断処理
}
else
return false;
}
のようにしていたのですが、「is演算子なんて封印してしまえばいいのに」と仰る方がいらしたので、「is演算子を使わない方がよいのか?」と、「現在のメソッドの形式に不備はないのだろうか?」ということが気になり質問させていただきました。
is演算子を使わないとなると、もう「typeof演算子」を利用する事くらいしか思いつきません。
主に「is演算子」を使っているのは「Equals」メソッドなので、とりあえず「Equal」メソッドだけで。上記メソッドに不備、改善点があればご指摘願います。
No.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()
という状態になってしまいます。
No.4
- 回答日時:
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 …
回答ありがとうございます。
そういえば「GetType」メソッドなんてすっかり忘れていました。要するにこれが質問に載せたコードの「is演算子」の代わりになるということですね。
一つ追加質問ですが、いいですか?
> isではEqualsの対称性が崩れます
についてですが、「is演算子」なら対象性が崩れ、「GetType」メソッドならそれを回避できるコードは、例えばどんなものがあるでしょうか? 参考にさせてもらいたいのですがいいでしょうか?
No.3
- 回答日時:
#1ですが、#2さんの回答を読んでちょっと前回の回答は過激だったかなと反省しております。
確かにダウンキャストを0にするためにメンテナンス不可能なくらい複雑怪奇な設計になってしまっては本末転倒ですね。
しかし、ダウンキャストは安易に使うべきではないというのは事実です。
使用するときはその前に、安易に使おうとしていないか、ダウンキャストを使わなくてもいいようにかつ明瞭なクラス設計に変更できないか、を考えてから使うべきでしょう。
No.2
- 回答日時:
基底クラスから派生クラスへの変換を「ダウンキャスト」と言います。
その逆は、「アップキャスト」と言います。
isやas演算子は、ダウンキャストのために用意されているもので、今回のケースは正当な使い方です。
一方、「is演算子なんて封印してしまえばいいのに」との回答は、
アップキャストしてポリモーフィズムすれば十分であるにも関わらず、わざわざダウンキャストしてis演算子で分岐していたため、「初心者に間違った使い方をさせるような代物ならいっそ禁止してしまえ」というちょっと過激な愚痴がつい出てしまったのでしょう。
ですが、is、as演算子はダウンキャストを行うためには必要なものです。
ダウンキャスト自体が本来避けるべきものですが、どうしても必要なケースもあります。
間違った使い方を誘発させるからと禁止しても、必要なときにバカ正直にルールに縛られて、より複雑なコードを書くのであれば、そちらの方がたちが悪いというものです。
(組織ではそれでもルールが優先されることもありますが…^^;)
要するに、道具は使いようってことです。
継承にしても演算子(orその他の言語の機能)にしても、使い方の「意図」によって良くも悪くもなりますので、適切な使い方を身につけてください。
No.1
- 回答日時:
あなたがその回答氏からそのように言われた質問を確認しました。
その上で氏の発言意図の推察込みで回答します。この場合、is演算子を利用することは問題ありません。
氏の発言は、あなたがその質問で安易にis演算子を使用してしまっていることを嘆いてのことだと思われます。
確かに、is演算子を使えば与えられたオブジェクトが自分の想定しているクラスであることを確認できます。しかし、そのような確認が本当に必要になるのは(今回のあなたの例のような)ごく少数で、前回の質問のあなたのコード例のように通常のコードに現れることはまずありません。
というか、is演算子は無いものとしてコーディングすべき(そして、それでどうしようもなくなったときに初めてis演算子を使用すべき)です。
なぜなら、isを乱用したコードはちっともオブジェクト指向になっていないからです。あなたが補足で書いたコードを覚えていますか? あれがis演算子を乱用した結果で、ちっともオブジェクト指向していないことはお分かりのはずです。
ですから、is演算子についてのアドバイスは以下の通りです。
・使うな。多分使用方法を間違えるから。(初心者向け)
・使うな。多分設計が間違っているから。(中級者向け)
・使うな。あなたなら使わずに何とかできるはずだ。(上級者向け)
・本当に他の手段は無いのか? ……仕方がない、使おう。(最上級者向け)
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
c# ネットワークプログラム
-
VB.NETで、DLLを頂いたんですが...
-
ダイアログ表示時にチェックボ...
-
既定のコンストラクタがない?
-
OnInitDialog()の関数の組み込み方
-
イベントにAddHandlerされてい...
-
エディットコントロールでEnter...
-
MFCのドラッグ&ドロップについて
-
FriendとPublicの違い。。。
-
リストコントロールをウィンド...
-
(UWSC) 「#32770」の意味わかり...
-
ダイアログクラスのコントロー...
-
privateなメンバ関数をテストす...
-
関数で値渡しと参照渡しではど...
-
ボタンのオーナードローについて
-
IncludeではなくClassで宣言す...
-
不要になった、普通の構造体の処理
-
CMainFrameクラスの使い方
-
Serialize で困ってます!!
-
DLLからEXEのクラスを呼び出す...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
条件によって別のクラスのイン...
-
c# ネットワークプログラム
-
ユーザーフォームのVBAエラー
-
excel vba グラフ データラベル...
-
C# フォームのShow()のオーバー...
-
VB.NETで、DLLを頂いたんですが...
-
c# Equalsメソッドについて
-
C# using の有効範囲
-
C#でstop()が使えない。
-
C#でVB.NETのReplaceコマンドを...
-
Eval関数を使いたい!ドキュメ...
-
VBA チェックボックスをオーバ...
-
FriendとPublicの違い。。。
-
イベントにAddHandlerされてい...
-
既定のコンストラクタがない?
-
ダイアログ表示時にチェックボ...
-
(UWSC) 「#32770」の意味わかり...
-
【ASP.NET】 独自で作成したク...
-
エディットコントロールでEnter...
-
クラスのアドレスを引数として...
おすすめ情報