我正在处理包含字符串数组的字典列表。字典是通过DataTable
上的循环定义/填充的。在下面的代码中,测试结果为false(两次),有人可以告诉我为什么吗?
List<Dictionary<string[], int>> mydix = new List<Dictionary<string[], int>>();
mydix.Add(new Dictionary<string[], int>());
mydix.Add(new Dictionary<string[], int>());
mydix.Add(new Dictionary<string[], int>());
string[] s = {"tree"};
mydix[1].Add(s, 1);
bool test = mydix[1].ContainsKey(s); // This evaluates to true, which I understand
var entry= mydix[1][s]; // This is 1
DataTable dt=new DataTable();
dt.Columns.Add("test");
dt.Rows.Add(new string[] {"key"});
mydix[2].Add(dt.Rows[0].ItemArray.Select(x => x.ToString()).ToArray(), 2);
test = mydix[2].ContainsKey(new string[] { "key" }); // Why does this evaluate to false?
// Here is an example with an array with two elements
DataTable dt2 = new DataTable();
dt2.Columns.Add("test");
dt2.Columns.Add("test2");
string[] t={"tree1","tree2"};
dt2.Rows.Add(t);
mydix[0].Add(dt2.Rows[0].ItemArray.Select(x => x.ToString()).ToArray(), 3);
test = mydix[0].ContainsKey(t); // Why does this evaluate to false?
答案 0 :(得分:1)
如果我错了,希望有人会纠正我,但我的理解是,当你致电ContainsKey
时,Dictionary
有一个私人方法(在dotPeek中探索),这决定了你比较的对象是否相同。
根据您对密钥使用的类型,将根据IEqualityComparer
的各种实现进行不同的相等比较,这样就可以根据您希望的类型运行最合适的比较比较
您正在使用字符串数组作为键,因此您实际上是在检查数组对象本身的相等性,而不是它们的内容。所以你的ContainsKey
返回false是完全正确的,你不是问你的Dictionary
它是否包含与键相同的数组,你问它是否包含不同的数组,这发生了包含相同的内容。
本例中的IEqualityComparer
GetHashCode
方法(数组)将根据对象的引用返回哈希值,而不是内容。
如果您想要这种行为,那么神奇的Skeet先生已在此帖子中为数组编写了一个自定义IEqualityComparer<T>
:
答案 1 :(得分:1)
问题在于,您用作字典键的字符串数组是对象比较,而不是内容比较。
为了支持此类数据作为密钥,最简单的解决方案是使用IEqualityComparer。
首先,创建比较器(这是一个示例;您的将需要额外的健全性检查和逻辑):
private class ArrayComparer : IEqualityComparer<string[]>
{
public bool Equals(string[] item1, string[] item2)
{
if (item1[0] == item2[0])
{
return true;
}
else
{
return false;
}
}
public int GetHashCode(string[] item)
{
return item[0].GetHashCode();
}
然后,更改字典的实例化以使用这个新的比较器:
mydix.Add(new Dictionary<string[], int>(new ArrayComparer()));
mydix.Add(new Dictionary<string[], int>(new ArrayComparer()));
mydix.Add(new Dictionary<string[], int>(new ArrayComparer()));
完成此操作后,两个测试都将返回true。