web-dev-qa-db-ja.com

タイプに関係なく、2つの整数オブジェクトが等しいかどうか比較する

2つのボックス化された整数(符号付きまたは符号なしのどちらでもかまいません)を比較して、等しいかどうかを疑問に思います。

たとえば、次のシナリオを見てください。

// case #1
object int1 = (int)50505;
object int2 = (int)50505;
bool success12 = int1.Equals(int2); // this is true. (pass)

// case #2
int int3 = (int)50505;
ushort int4 = (ushort)50505;
bool success34 = int3.Equals(int4); // this is also true. (pass)

// case #3
object int5 = (int)50505;
object int6 = (ushort)50505;
bool success56 = int5.Equals(int6); // this is false. (fail)

この方法でボックス化整数型を確実に比較する方法に困惑しています。実行時までそれらが何であるかはわかりません。また、longの可能性があるため、両方をulongにキャストすることはできません。また、どちらか一方が負の値になる可能性があるため、両方をulongに変換することもできません。

私が思いつくことができる最良のアイデアは、一般的なタイプが見つかるか、それらが等しくないことを除外できるまで、試行錯誤を繰り返してキャストすることです。これは理想的なソリューションではありません。

29
caesay

ケース2では、ushortは暗黙的にintに変換できるため、実際にはint.Equals(int)を呼び出すことになります。このオーバーロードの解決はコンパイル時に実行されます。コンパイラは_int5_と_int6_のタイプをobjectとしてしか認識しないため、object.Equals(object)...を呼び出すため、ケース3では使用できません。 2つのオブジェクトのタイプが異なる場合、_object.Equals_はfalseを返します。

あなたcould動的型付けを使用して、実行時に同じ種類のオーバーロード解決を実行しますが、次のようなことを試みた場合でも問題が発生します。

_dynamic x = 10;
dynamic y = (long) 10;
Console.WriteLine(x.Equals(y)); // False
_

ここでは、longを処理するオーバーロードがないため、通常の_object.Equals_を呼び出します。

1つのオプションは、値をdecimalに変換することです。

_object x = (int) 10;
object y = (long) 10;
decimal xd = Convert.ToDecimal(x);
decimal yd = Convert.ToDecimal(y);
Console.WriteLine(xd == yd);
_

これは、ulonglongの比較も処理します。

すべてのプリミティブ整数型のすべての値を正確に表すことができるため、decimalを選択しました。

36
Jon Skeet

整数は 型です。 2つの整数型を比較す​​るとき、コンパイラはそれらのをチェックします。

オブジェクトは 参照 タイプです。 2つのオブジェクトを比較すると、コンパイラはそれらの参照をチェックします。

興味深い部分はここにあります:

 object int5 = (int)50505; 

コンパイラーのパフォーマンス boxing 操作、値の型を参照型にラップし、Equalsは値ではなく参照を比較します。

0
Kovalenko Ivan