Comparaisons de type de valeur en boîte

Ce que je tente d’obtenir ici est une comparaison directe des valeurs des types primitifs en boîte.

((object)12).Equals((object)12); // Type match will result in a value comparison, ((object)12).Equals((object)12d); // but a type mismatch will not. (false) object.Equals((object)12,(object)12d); // Same here. (false) 

Je comprends le “pourquoi”. Je ne vois tout simplement pas comment.

Les types sont inconnus jusqu’à l’exécution, où ils pourraient être n’importe quel type primitif d’une source de données. Cela inclut les chaînes, les dates-heures, les bools, etc. Je me suis lancé dans la mauvaise voie pour écrire une méthode d’extension qui traite les deux types, puis jette avant de faire une comparaison ‘==’: (Par souci d’exhaustivité, j’ai inclus chaque type primitif , plus ceux qui m’intéressaient)

 public static bool ValueEquals(this object thisObj, object compare) { if (thisObj is int) { int obj = (int)thisObj; if (compare is int) return (obj == (int)compare); if (compare is uint) return (obj == (uint)compare); if (compare is decimal) return (obj == (decimal)compare); if (compare is float) return (obj == (float)compare);  } if (thisObj is uint) { uint obj = (uint)thisObj; if (compare is int) return (obj == (int)compare); if (compare is uint) return (obj == (uint)compare);  } if (thisObj is decimal) { decimal obj = (decimal)thisObj; if (compare is int) return (obj == (int)compare);  

La méthode résultante s’est avérée être plus de 300 lignes, ce qui était bien (encore hideux), mais maintenant je dois faire plus que simplement ‘==’. J’ai besoin de>, <, =,! =.

Existe-t-il quelque chose dans Reflection que je pourrais utiliser pour les comparaisons de types de valeur en boîte?

Rien du tout?

On dirait que vous supposez que le type de arg1 est celui que vous voulez convertir, alors j’utiliserais un génrique comme celui-ci. Tant que arg2 est IConvertible (int, double, tous les nombres, chaîne, etc. sont tous IConvertible), cela fonctionnera:

 public static bool ValueEquality(T1 val1, T2 val2) where T1 : IConvertible where T2 : IConvertible { // convert val2 to type of val1. T1 boxed2 = (T1) Convert.ChangeType(val2, typeof (T1)); // compare now that same type. return val1.Equals(boxed2); } 

** UPDATE ** Fait les deux types génériques args, peut être déduit et ajoute plus de sécurité en temps de compilation sur arg2 pour s’assurer qu’il est IConvertible au moment de la compilation.

Étant donné cette fonction générique, tous les éléments suivants renvoient maintenant la valeur true (il n’est pas nécessaire de spécifier l’argument de type, car inféré du premier argument:

  Console.WriteLine(ValueEquality(1, "1")); Console.WriteLine(ValueEquality(2, 2.0)); Console.WriteLine(ValueEquality(3, 3L)); 

METTRE À JOUR

En fonction de votre commentaire, voici une surcharge si tout ce que vous avez sont des objects. Les deux peuvent coexister et il appellera celui plus approprié en fonction des arguments:

  public static bool ValueEquality(object val1, object val2) { if (!(val1 is IConvertible)) throw new ArgumentException("val1 must be IConvertible type"); if (!(val2 is IConvertible)) throw new ArgumentException("val2 must be IConvertible type"); // convert val2 to type of val1. var converted2 = Convert.ChangeType(val2, val1.GetType()); // compare now that same type. return val1.Equals(converted2); } 

Et cela fonctionnera pour object:

  object obj1 = 1; object obj2 = 1.0; Console.WriteLine(ValueEquality(obj1, obj2)); 

Comme je l’ai dit, les deux peuvent coexister en tant que surcharges. Par conséquent, si vous comparez directement des types IConvertible compatibles, le générique sera utilisé, et si vous avez simplement des types encadrés en tant qu’object, les surcharges seront utilisées.

Envisagez d’utiliser IComparable au lieu de if manuel – http://msdn.microsoft.com/en-us/library/system.icomparable.compareto.aspx .

Si vous avez besoin de quelque chose de similaire à l’avenir, considérez swith sur les types d’un opérande en premier et implémentez la classe “gestionnaire d’opérations” pour chacun des types avec méthode pour gérer l’opération comme IntOpHandler.PerformOp(int left, object right) .

Vous pouvez également souvent réduire le nombre de types à traiter en fusionnant d’abord plusieurs types (octets, short, ushort, int, uint, long long, puis long).