等値性(等価性)と同一性
関連ネタで。
同一性は同じオブジェクトかどうかの比較、等価性は中身が同じ値かどうかの比較。ポインタが基本の言語ならポインタの比較で同一性の比較、中身の比較は等価性と、それぞれ明示的でわかりやすい。参照が基本の言語だと、どちらの比較なのかが==やEqualsの中に隠れてしまって非常にわかりづらい。
原則は、box化していない値型は当然だけど値の比較、参照型は一般的に同一性の比較。ただし、値をあらわす参照型に限っては値の比較がよいとガイドラインに記述があります。
表にしてみた。
でも、C#は==もEqualsも各クラスで再定義できるので、この表を見るんじゃなく、いちいちリファレンスを見るべきです。表は参考程度で。
== | x.Equals( x ) | Equals( x, x ) | ReferenceEquals( x, x ) | |
---|---|---|---|---|
組み込みの値型 | 等値性 | 等値性 | - | - |
NaN ( double, float ) (注:IsNaNを使うべき) |
等値性 ただし常に False |
等値性 ただし常に True |
- [box化して等値性を 調べると True] |
- |
ユーザ定義の値型 ( struct ) |
ユーザ定義がなければ コンパイルエラー (ユーザ定義は 等値性 であるべき) |
- (ユーザ定義は 等値性 であるべき) [ユーザ定義がなければ 等値性 ( box化を伴い,リフレクションを使う )] |
- (ユーザ定義は 等値性 であるべき) [ユーザ定義がなければ 等値性 ( box化を伴い,リフレクションを使う )] |
- |
box化した値型 | 同一性 | 等値性 | 等値性 | 同一性 [box化していない一つの値を比較しようとしても 各々boxされるため、同一にはならない] |
string | 等値性 | 等値性 | 等値性 | 同一性 |
class | (基本的に) 同一性 | (基本的に) 同一性 | (基本的に) 同一性 | 同一性 |
値を表す class 例えばUriなど |
等値性 (であるべき) | 等値性 (であるべき) | 等値性 (であるべき) | 同一性 |
よくやるのはbox化した値型の==ではまるパターン。C#のいけてないとこワースト10に入ると思う。
==とEqualsはどっちがいいの?ってのは、原則==。
コードの見た目がシンプル、できるILもシンプル(場合によるけど)、菊池さんの指摘(関連)、これらから==。
ちなみに、stringの比較は Equals( string a, string b, StringComparison comparisonType ) のみを使うってのがいいかも。必ず3引数のもの限定で。見やすくはないけど、stringの比較って複雑な動作なのに知らないで使ってる人が多そうだし。
(追記)ちょっと修正。stringの等値性の比較はcompare等の比較と違って、シンプルだから↑の主張はひっこめます。失礼しました。(追記終わり)
関連
http://www.divakk.co.jp/blog/aoyagi/archive/2005/03/25/1879.aspx
- Object.Equals メソッド (Object)
- Object.Equals メソッド (Object, Object)
- Object.ReferenceEquals メソッド (System)
- ValueType.Equals メソッド (Object)
- == 演算子 (C# リファレンス)
- Equals() と演算子 == のオーバーロードに関するガイドライン (C#)
- クラスライブラリ開発のデザインガイドライン Equals および等値演算子 (==) 実装のガイドライン
- クラスライブラリ開発のデザインガイドライン Equals メソッドの実装
ガイドライン多杉。Equalsと==が違う場合を許容しているのはおかしいと思う。NaNがどうしようもないから許容なんだろうな。