LoginSignup
2
2

More than 3 years have passed since last update.

[.NET] コードを見直したくなる「値型」等価判定の思わぬ落とし穴(一般編)

Last updated at Posted at 2019-01-20

値型の等価判定には気をつけるべき点があります。
以下の例で、Assert.IsTrue なら () 内が 真、Assert.IsFalse なら () 内が 偽です。
★印の箇所は注意が必要です。

ボックス化した値の比較

int i = 1;
object o1 = i;
object o2 = i;

// Object.Equals が int の Equals を呼び出すので値で比較されます。
Assert.IsTrue(o1.Equals(o2));

// o1 != o2 かつ o1 != null なら上の o1.Equals(o2) と同じ結果となります。
Assert.IsTrue(Object.Equals(o1, o2));

ここまではいいでしょう。
次は少し注意が必要です。

// ★ボックス化(値型 → object)すると参照比較になるので一致しません。
Assert.IsFalse(o1 == o2);

// ★引数として渡されるときにボックス化されるので一致しません。
Assert.IsFalse(Object.ReferenceEquals(1, 1));
Assert.IsFalse(Object.ReferenceEquals(i, i));

DataRow の各フィールド値(インデクサ/Itemプロパティ)なども Object 型なので、比較の際は注意しましょう。

異なる型の比較

int i = 1;
long l = 1;

// 比較演算子では、int が long に暗黙的に型変換され、long 同士として比較されます。
Assert.IsTrue(i == l);
Assert.IsTrue(l == i);

// 暗黙の型変換ができるなら Equals で比較できます。
Assert.IsTrue(l.Equals(i));

ここまではいいでしょう。
以降は注意が必要です。

// ★暗黙の型変換ができないと Equals は false を返します。
// コンパイルは通り、例外も発生しないので見逃しがちです。
Assert.IsFalse(i.Equals(l));

// ★異なる型へのボックス化解除は失敗します。
object iBoxed = i;
try
{
   // int 型をボックス化しているので long 型に戻すことはできません。(InvalidCastException が発生)
   bool b = (l == (long)iBoxed);
   Assert.Fail();
}
catch (InvalidCastException) {}

おまけです。

// 実行されるのは Object.Equals です。
// 字面だけ見ると true を期待してしまいそう(?)です。
Assert.IsFalse(Type.Equals(1, 2));

値型を自作する場合の注意点

値型(struct/Structure)の Equals メソッドは、既定ではリフレクションを使用して全フィールド(自動実装プロパティのバッキングフィールドを含む)を定義された型の Equals メソッドで比較します。
値型を自分で作成する場合、Equals メソッドをオーバーライドすることで、この比較処理をカスタマイズすることができます。

等価演算子(==)を使用するためには、「==」「!=」のオーバーロードを定義する必要があります。

値型を定義する場合には、Equals メソッドのオーバーライドと等価演算子のオーバーロードが推奨されています。

《参考》コード分析(FxCop)
CA1815: equals および operator equals を値型でオーバーライドします


[.NET] 値型 等価判定の思わぬ落とし穴(一般編)
[.NET] 値型 等価判定の思わぬ落とし穴(特殊編)
[.NET] 参照型 等価判定の思わぬ落とし穴(一般編)
[.NET] 参照型 等価判定の思わぬ落とし穴(特殊編)

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2