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
不是只读的,所以使用它而不是concreateDictionary
,不会隐藏太多内容) 我使用了一种扩展方法来检查两个序列中是否有相同的项
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);