web-dev-qa-db-fra.com

Comparer deux objets entiers pour l'égalité quel que soit le type

Je me demande comment vous pourriez comparer deux entiers encadrés (qui peuvent être signés ou non signés) l'un à l'autre pour l'égalité.

Par exemple, jetez un œil à ce scénario:

// 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)

Je suis perplexe sur la façon de comparer de manière fiable les types d'entiers encadrés de cette façon. Je ne saurai pas ce qu'ils sont avant l'exécution, et je ne peux pas simplement les convertir tous les deux en long, car l'un pourrait être un ulong. Je ne peux pas non plus simplement les convertir tous les deux en ulong parce que l'un pourrait être négatif.

La meilleure idée que j'ai pu trouver est de simplement lancer un essai et une erreur jusqu'à ce que je puisse trouver un type commun ou exclure qu'ils ne sont pas égaux, ce qui n'est pas une solution idéale.

29
caesay

Dans le cas 2, vous finissez par appeler int.Equals(int), car ushort est implicitement convertible en int. Cette résolution de surcharge est effectuée au moment de la compilation. Il n'est pas disponible dans le cas 3 car le compilateur ne connaît que le type de int5 Et int6 Comme object, donc il appelle object.Equals(object)... et c'est naturel que object.Equals renverra false si les types des deux objets sont différents.

Vous pourriez utiliser le typage dynamique pour effectuer le même type de résolution de surcharge au moment de l'exécution - mais vous auriez toujours un problème si vous essayiez quelque chose comme:

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

Ici, il n'y a pas de surcharge qui gérera long, donc il appellera le object.Equals Normal.

Une option consiste à convertir les valeurs en decimal:

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

Cela gérera également la comparaison de ulong avec long.

J'ai choisi decimal car il peut représenter exactement chaque valeur de chaque type entier primitif.

36
Jon Skeet

L'entier est un type valeur . Lorsque vous comparez deux types d'entiers, le compilateur vérifie leurs valeurs .

L'objet est de type référence . Lorsque vous comparez deux objets, le compilateur vérifie leurs références .

La partie intéressante est ici:

 object int5 = (int)50505; 

Compiler perfoms boxing operation, encapsule le type de valeur dans le type de référence, et Equals comparera les références, pas les valeurs.

0
Kovalenko Ivan