C# .NET字典具有相同的键和值,但不是';";“相等”;

C# .NET字典具有相同的键和值,但不是';";“相等”;,c#,.net,dictionary,equality,C#,.net,Dictionary,Equality,此测试失败: using Microsoft.VisualStudio.TestTools.UnitTesting; [TestMethod()] public void dictEqualTest() { IDictionary<string, int> dict = new Dictionary<string, int>(); IDictionary<string, int>

此测试失败:

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
    }
使用Microsoft.VisualStudio.TestTools.UnitTesting;
[TestMethod()]
公开无效口述测试(){
IDictionary dict=新字典();
IDictionary dictClone=新字典();
对于(int x=0;x<3;x++){
dict[x.ToString()]=x;
dictClone[x.ToString()]=x;
}
Assert.AreEqual(dict,dictClone);//此处失败
Assert.IsTrue(dict.Equals(dictClone));//这里,如果第一个被注释掉
Assert.arame(dict,dictClone);//也失败
}
我是否误解了
词典的工作原理


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

问题在于这行代码:

Assert.AreEqual(dict, dictClone)

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

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


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

字典类不会覆盖
对象。从MSDN doco中可以看出,Equals
方法:

确定指定的 对象等于当前对象

看到您正在进行单元测试,您的
Assert
类应该提供一个测试方法来测试两个集合是否相同

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

编辑字典实现了
ICollection
接口,你能看看这是否管用吗?您可能需要使用来比较两个词典条目

EDITHmm IDictionary没有实现
ICollection
,这有点麻烦。然而,这是可行的(尽管是一种黑客行为):

IDictionary dict=new Dictionary();
IDictionary dictClone=新字典();
对于(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
,不会隐藏太多内容)

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

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;
}
公共静态bool CheckForEquality(此IEnumerable源,IEnumerable目标)
{
if(source.Count()!=destination.Count())
{
返回false;
}
var dictionary=newdictionary();
foreach(源中的var值)
{
如果(!dictionary.ContainsKey(值))
{
字典[值]=1;
}
其他的
{
字典[值]+;
}
}
foreach(目标中的var成员)
{
如果(!dictionary.ContainsKey(成员))
{
返回false;
}
字典[成员]——;
}
foreach(字典中的var kvp)
{
如果(kvp.Value!=0)
{
返回false;
}
}
返回true;
}

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

试试这个

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

在.Net 3.5及更高版本中提供了一些功能,如
.ToList()
,它们可以将字典转换为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).     
IDictionary d1=新词典{
{“a”,“1”},{“b”,“2”},{“c”,“3”};
IDictionary d2=新词典{
{“b”,“2”},{“a”,“1”},{“c”,“3”};//相同的键值,不同的顺序
IDictionary d3=新词典{
{“a”,“1”},{“d”,“2”},{“c”,“3”};//第二个元素的键与d1不同
IDictionary d4=新词典{
{“a”,“1”},{“b”,“4”},{“c”,“3”};//第二个元素的值与d1不同
CollectionAssert.AreEquivalent(d1.ToList(),d2.ToList());
//CollectionAssert.AreEquivalent(d1.ToList(),d3.ToList());//失败!
//CollectionAssert.AreEquivalent(d1.ToList(),d4.ToList());//失败!
//如果未注释,上述两项测试将失败并出现错误:
//CollectionAssert.AreEquivalent失败。所需的集合包含1
//事故的发生。实际集合包含0个事件。

NUnit类
CollectionAssert
有一个

CollectionAssert.AreEquivalent(dict, dictClone);

因为
Dictionary
实现了
IEnumerable

,所以我会从堆栈跟踪开始——调用哪个方法是相等的?顺便问一下,这是MBUnit、NUnit、MS Test/other吗?这是内置的Visual Studio 2008 Pro单元测试。+1,此外,我不确定MS的测试套件是否有集合比较工具,但我非常确定NUnit有。这可能是因为您没有明显地突出显示失败的部分。(2年前,当你回答时,我认为这是显而易见的。)@SixlettVariables——这在2年前对我来说似乎是显而易见的,现在仍然如此。我的意思是,我在解释的正上方有一条突出显示的线,不确定我还能做什么。这也让我感到困惑-看起来这可能是一个建议的解决方案-我编辑了原始答案以澄清。看起来不错。但是如何将
字典
转换为
ICollection
ICollection
只有一个类型参数
CollectionAssert.AreEquivalent(dict, dictClone);