
こんにちは、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で質問しましょう!
似たような質問が見つかりました
- Java java 飾子を付けること(public static・・・) ・コンソールへの出力処理はmainメ 2 2022/06/16 19:34
- Visual Basic(VBA) Visual Basic : ImageListの画像がそろったときにメッセージを表示 1 2023/07/20 13:53
- C言語・C++・C# C#テキストボックスの文字を配列にいれてその後表示する 4 2022/07/17 04:47
- Java javaの質問です 次の機能を有するメソッド4つを自クラスに作成し、実装したいです 【機能】 足し算 1 2022/06/15 17:49
- その他(プログラミング・Web制作) pythonのプログラムについての質問です。 1 2023/05/26 10:31
- その他(プログラミング・Web制作) pythonでクラスで複数のメソッドを利用する方法 2 2022/04/15 04:17
- C言語・C++・C# leetcode 155 minstack 1 2022/05/07 16:43
- Java java 次の機能を有するメソッドを自クラスに作成し、実装したいです。 機能 名前判定機能 →名前が 3 2022/06/16 16:08
- Visual Basic(VBA) 【Excel VBA】自動メール送信の機能追加 5 2022/09/29 12:53
- PHP ここで言う「アロー演算子」の役割を教えてください。 1 2022/03/26 02:38
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
c# Equalsメソッドについて
-
C#でstop()が使えない。
-
VBA チェックボックスをオーバ...
-
一クラス何ステップ以上で読む...
-
任意の解像度のメモリデバイス...
-
VB6.0の関数をC++で使いたい
-
コンストラクタについて
-
VisualStudio2005
-
【VC++】クラスの追加方法について
-
ダイアログ表示時にチェックボ...
-
C++でのDirectXプログラミング...
-
正規表現 [^/]+ の意味を教えて
-
C# panel内のコントロールの使...
-
Visual studio express 2013 ...
-
クラスプロジェクトのデバッグ
-
MFC VC++ 6.0 使用
-
Serialize で困ってます!!
-
VB6では、Applicationは未定義...
-
コレクションクラスでクラスを...
-
VB.Netの大域変数
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
c# ネットワークプログラム
-
ユーザーフォームのVBAエラー
-
excel vba グラフ データラベル...
-
条件によって別のクラスのイン...
-
VB.NETで、DLLを頂いたんですが...
-
C# フォームのShow()のオーバー...
-
Eval関数を使いたい!ドキュメ...
-
c# nullは空集合として扱かって...
-
C# using の有効範囲
-
C# でフォームやクラスを利用...
-
MSDNのリファレンスの見方が分...
-
C#でVB.NETのReplaceコマンドを...
-
C#で別スレッドからメインform...
-
BCB5:フォームに自作のプロパ...
-
プロパティについて
-
c# でList<T>と似たものを作りたい
-
ConsoleApplicationから別プロ...
-
VBA チェックボックスをオーバ...
-
FriendとPublicの違い。。。
-
既定のコンストラクタがない?
おすすめ情報