Help us understand the problem. What is going on with this article?

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

値型の等価判定には気をつけるべき点があります。
以下の例で、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] 参照型 等価判定の思わぬ落とし穴(特殊編)

CodeOne
【品質と生産性にこだわるシステム開発】 .NET(C#/VB.NET)専門・リモート開発歴10年。即日・1時間から頼める常駐しないエンジニア。確かな技術で開発チームを手堅くサポートいたします。
https://codeone.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした