Les dictionnaires .NET ont les mêmes clés et valeurs, mais ne sont pas «égaux»

Ce test échoue:

using Microsoft.VisualStudio.TestTools.UnitTesting; [TestMethod()] public void dictEqualTest() { IDictionary dict = new Dictionary(); IDictionary dictClone = new Dictionary(); for (int x = 0; x < 3; x++) { dict[x.ToString()] = x; dictClone[x.ToString()] = x; } Assert.AreEqual(dict, dictClone); // fails here Assert.IsTrue(dict.Equals(dictClone)); // and here, if the first is commented out Assert.AreSame(dict, dictClone); // also fails } 

Est-ce que je comprends mal le fonctionnement d’un Dictionary ?

Je cherche l’équivalent Java de .equals() , sans essayer de vérifier l’égalité référentielle.

La classe de dictionnaire ne remplace pas la méthode Object.Equals telle que vue depuis le doco MSDN:

http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

Détermine si l’object spécifié est égal à l’object actuel.

Voyant que vous effectuez des tests unitaires, votre classe Assert doit fournir une méthode de test permettant de tester si deux collections sont identiques.

Microsoft Unit testing framework fournit la classe CollectionAssert dans le but de comparer des collections:

http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.collectionassert_members%28VS.80%29.aspx

EDIT Dictionary implémente l’interface ICollection , pouvez-vous voir si cela fonctionne? Vous devrez peut-être utiliser cette surcharge pour comparer deux entrées de dictionnaire.

EDIT Hmm IDictionary n’implémente pas ICollection , ce qui est un peu pénible. Cela fonctionne cependant (bien que ce soit un hack):

 IDictionary dict = new Dictionary(); IDictionary dictClone = new Dictionary(); for(int x = 0; x < 3; x++) { dict[x.ToString()] = x; dictClone[x.ToString()] = x; } CollectionAssert.AreEqual((System.Collections.ICollection)dict, (System.Collections.ICollection)dictClone); 

L'approche ci-dessus fonctionnera pour les instances de Dictionary . Toutefois, si vous testez une méthode qui renvoie IDictionary elle pourrait échouer si l'implémentation change. Mon conseil est de changer le code pour utiliser Dictionary au lieu d' IDictionary (puisque IDictionary n'est pas en lecture seule, vous ne cachez donc pas beaucoup en l'utilisant à la place de concreate Dictionary ).

Si vous êtes spécifiquement intéressé par la façon de résoudre ce problème du sharepoint vue des tests unitaires:

Essaye ça

 CollectionAssert.AreEquivalent(dict.ToList(), dictClone.ToList()); 

Explication

Il existe des méthodes d’extension sur IDictionary , telles que .ToList() , disponibles dans les versions .Net 3.5 et supérieures, qui convertissent le dictionnaire en une collection de KeyValuePair pouvant être facilement comparée à CollectionAssert.AreEquivalent .

Ils vont même donner des messages d’erreur raisonnablement utiles! Exemple d’utilisation:

 IDictionary d1 = new Dictionary { { "a", "1"}, {"b", "2"}, {"c", "3"}}; IDictionary d2 = new Dictionary { {"b", "2"}, { "a", "1"}, {"c", "3"}}; // same key-values, different order IDictionary d3 = new Dictionary { { "a", "1"}, {"d", "2"}, {"c", "3"}}; // key of the second element differs from d1 IDictionary d4 = new Dictionary { { "a", "1"}, {"b", "4"}, {"c", "3"}}; // value of the second element differs from d1 CollectionAssert.AreEquivalent(d1.ToList(), d2.ToList()); //CollectionAssert.AreEquivalent(d1.ToList(), d3.ToList()); // fails! //CollectionAssert.AreEquivalent(d1.ToList(), d4.ToList()); // fails! // if uncommented, the 2 tests above fail with error: // CollectionAssert.AreEquivalent failed. The expected collection contains 1 // occurrence(s) of <[b, 2]>. The actual collection contains 0 occurrence(s). 

Le problème est avec cette ligne de code:

 Assert.AreEqual(dict, dictClone) 

Vous comparez des références d’object, qui ne sont pas égales.

J’ai utilisé une méthode d’extension qui vérifie deux séquences pour des éléments égaux

 public static bool CheckForEquality(this IEnumerable source, IEnumerable destination) { if (source.Count() != destination.Count()) { return false; } var dictionary = new Dictionary(); foreach (var value in source) { if (!dictionary.ContainsKey(value)) { dictionary[value] = 1; } else { dictionary[value]++; } } foreach (var member in destination) { if (!dictionary.ContainsKey(member)) { return false; } dictionary[member]--; } foreach (var kvp in dictionary) { if (kvp.Value != 0) { return false; } } return true; } 

Vous ne comprenez absolument pas comment fonctionnent les types de référence.

Dictionary ne remplace pas object.Equals() . Ainsi, il utilise une égalité de référence – en gros, si les deux références pointent vers la même instance, elles sont égales sinon elles ne le sont pas.