アプリ版:「スタンプのみでお礼する」機能のリリースについて

 こんにちは、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」メソッドだけで。上記メソッドに不備、改善点があればご指摘願います。

A 回答 (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()
という状態になってしまいます。
    • good
    • 0
この回答へのお礼

 回答ありがとうございます。

 追加質問に対する例が確かに書いてありましたが、気づいていませんでした。いろいろと勉強になりました。

お礼日時:2012/03/27 22:10

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 …
    • good
    • 0
この回答へのお礼

 回答ありがとうございます。

 そういえば「GetType」メソッドなんてすっかり忘れていました。要するにこれが質問に載せたコードの「is演算子」の代わりになるということですね。

 一つ追加質問ですが、いいですか?

> isではEqualsの対称性が崩れます

 についてですが、「is演算子」なら対象性が崩れ、「GetType」メソッドならそれを回避できるコードは、例えばどんなものがあるでしょうか? 参考にさせてもらいたいのですがいいでしょうか?

お礼日時:2012/03/27 15:50

#1ですが、#2さんの回答を読んでちょっと前回の回答は過激だったかなと反省しております。


確かにダウンキャストを0にするためにメンテナンス不可能なくらい複雑怪奇な設計になってしまっては本末転倒ですね。

しかし、ダウンキャストは安易に使うべきではないというのは事実です。
使用するときはその前に、安易に使おうとしていないか、ダウンキャストを使わなくてもいいようにかつ明瞭なクラス設計に変更できないか、を考えてから使うべきでしょう。
    • good
    • 0
この回答へのお礼

 回答ありがとうございます。

 ダウンキャストはほどほどにと。勉強になりました。

お礼日時:2012/03/27 15:44

基底クラスから派生クラスへの変換を「ダウンキャスト」と言います。


その逆は、「アップキャスト」と言います。

isやas演算子は、ダウンキャストのために用意されているもので、今回のケースは正当な使い方です。
一方、「is演算子なんて封印してしまえばいいのに」との回答は、
アップキャストしてポリモーフィズムすれば十分であるにも関わらず、わざわざダウンキャストしてis演算子で分岐していたため、「初心者に間違った使い方をさせるような代物ならいっそ禁止してしまえ」というちょっと過激な愚痴がつい出てしまったのでしょう。

ですが、is、as演算子はダウンキャストを行うためには必要なものです。
ダウンキャスト自体が本来避けるべきものですが、どうしても必要なケースもあります。
間違った使い方を誘発させるからと禁止しても、必要なときにバカ正直にルールに縛られて、より複雑なコードを書くのであれば、そちらの方がたちが悪いというものです。
(組織ではそれでもルールが優先されることもありますが…^^;)
要するに、道具は使いようってことです。
継承にしても演算子(orその他の言語の機能)にしても、使い方の「意図」によって良くも悪くもなりますので、適切な使い方を身につけてください。
    • good
    • 0
この回答へのお礼

 回答ありがとうございます。

 要はc#の機能を使いこなせるかどうかってことですね。使われているうちは要注意と。

お礼日時:2012/03/27 15:43

あなたがその回答氏からそのように言われた質問を確認しました。

その上で氏の発言意図の推察込みで回答します。

この場合、is演算子を利用することは問題ありません。
氏の発言は、あなたがその質問で安易にis演算子を使用してしまっていることを嘆いてのことだと思われます。

確かに、is演算子を使えば与えられたオブジェクトが自分の想定しているクラスであることを確認できます。しかし、そのような確認が本当に必要になるのは(今回のあなたの例のような)ごく少数で、前回の質問のあなたのコード例のように通常のコードに現れることはまずありません。
というか、is演算子は無いものとしてコーディングすべき(そして、それでどうしようもなくなったときに初めてis演算子を使用すべき)です。

なぜなら、isを乱用したコードはちっともオブジェクト指向になっていないからです。あなたが補足で書いたコードを覚えていますか? あれがis演算子を乱用した結果で、ちっともオブジェクト指向していないことはお分かりのはずです。

ですから、is演算子についてのアドバイスは以下の通りです。
・使うな。多分使用方法を間違えるから。(初心者向け)
・使うな。多分設計が間違っているから。(中級者向け)
・使うな。あなたなら使わずに何とかできるはずだ。(上級者向け)
・本当に他の手段は無いのか? ……仕方がない、使おう。(最上級者向け)
    • good
    • 0
この回答へのお礼

 回答ありがとうございます。

 なるほど。is演算子は結構きびしいのですね。

お礼日時:2012/03/27 15:41

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!