19

此测试失败:

using Microsoft.VisualStudio.TestTools.UnitTesting;        

[TestMethod()]
        public void dictEqualTest() {
            IDictionary<string, int> dict = new Dictionary<string, int>();
            IDictionary<string, int> dictClone = new Dictionary<string, int>();

        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
    }

我对 a 的Dictionary工作方式有误解吗?

我正在寻找 Java 等价物.equals(),而不是试图检查引用相等性。

4

6 回答 6

24

字典类不会覆盖Object.Equals从 MSDN doco 中看到的方法:

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

确定指定的 Object 是否等于当前的 Object。

看到你在做单元测试,你的Assert类应该提供一个测试方法来测试两个集合是否相同。

Microsoft 单元测试框架提供了CollectionAssert用于比较集合的类:

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

编辑字典实现ICollection接口,你能看看它是否有效吗?您可能需要使用此重载来比较两个字典条目。

EDIT Hmm IDictionary 没有实现ICollection,这有点痛苦。然而,这有效(尽管是 hack):

IDictionary<string, int> dict = new Dictionary<string, int>();
IDictionary<string, int> dictClone = new Dictionary<string, int>();

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

上述方法适用于 的实例Dictionary,但是如果您正在测试返回的方法,IDictionary如果实现发生更改,它可能会失败。我的建议是更改要使用的代码,Dictionary而不是IDictionary(因为IDictionary不是只读的,所以你不会通过使用它而不是 concreate 来隐藏那么多Dictionary)。

于 2010-02-08T00:56:12.753 回答
13

如果您对如何从单元测试的角度解决此问题特别感兴趣:

试试这个

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

解释

IDictionary 上有一些扩展方法- 例如.ToList()- 在 .Net 3.5 及更高版本中可用,它将字典转换为 KeyValuePair 的集合,可以轻松地与CollectionAssert.AreEquivalent.

他们甚至会给出相当有用的错误信息!示例用法:

IDictionary<string, string> d1 = new Dictionary<string, string> {
    { "a", "1"}, {"b", "2"}, {"c", "3"}};

IDictionary<string, string> d2 = new Dictionary<string, string> {
    {"b", "2"}, { "a", "1"}, {"c", "3"}}; // same key-values, different order

IDictionary<string, string> d3 = new Dictionary<string, string> {
    { "a", "1"}, {"d", "2"}, {"c", "3"}}; // key of the second element differs from d1

IDictionary<string, string> d4 = new Dictionary<string, string> {
    { "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).     
于 2012-06-18T14:17:23.060 回答
7

问题在于这行代码:

Assert.AreEqual(dict, dictClone)

您正在比较不相等的对象引用。

于 2010-02-08T00:54:33.750 回答
4

我使用了一种扩展方法来检查两个序列是否有相同的项目

public static bool CheckForEquality<T>(this IEnumerable<T> source, IEnumerable<T> destination)
{
    if (source.Count() != destination.Count())
    {
        return false;
    }

    var dictionary = new Dictionary<T, int>();

    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;
}
于 2010-02-08T01:20:59.083 回答
1

您完全不了解引用类型是如何工作的。

Dictionary不覆盖object.Equals(). 因此,它使用引用相等 - 基本上,如果两个引用都指向同一个实例,则它们相等,否则它们不相等。

于 2010-02-08T00:55:00.537 回答
0

NUnit 类CollectionAssert有一个AreEquivalent接受IEnumerable参数的方法,所以在这种情况下它很简单

CollectionAssert.AreEquivalent(dict, dictClone);

因为Dictionary实现IEnumerable.

于 2020-04-03T08:32:48.993 回答