C# 如何在C中使用基元列表或列表作为字典的键#

C# 如何在C中使用基元列表或列表作为字典的键#,c#,dictionary,C#,Dictionary,我试图使用int数组作为C#中的键,而我看到的行为(对我来说)是出乎意料的 var result=newdictionary(); 结果[新[]{1,1}]=100; 结果[新[]{1,1}]=200; Assert.AreEqual(1,result.Count);//false是2 列表也一样 var result = new Dictionary<List<int>, int>(); result[new List<int> { 1, 1 }] = 1

我试图使用int数组作为C#中的键,而我看到的行为(对我来说)是出乎意料的

var result=newdictionary();
结果[新[]{1,1}]=100;
结果[新[]{1,1}]=200;
Assert.AreEqual(1,result.Count);//false是2
列表也一样

var result = new Dictionary<List<int>, int>();
result[new List<int> { 1, 1 }] = 100;
result[new List<int> { 1, 1 }] = 200;

Assert.AreEqual(1, result.Count); // false is 2
var result=newdictionary();
结果[新列表{1,1}]=100;
结果[新列表{1,1}]=200;
Assert.AreEqual(1,result.Count);//false是2
我希望字典使用Equals来确定地图中是否存在一个键。事实似乎并非如此


有人能解释一下为什么以及如何让这种行为起作用吗?

您正在将新的对象(数组或列表)作为键传递。作为一个新对象,它有一个不同的引用,因此它被接受为新键。

您将新对象(数组或列表)作为键传递。作为一个新的对象,它有一个不同的引用,因此被接受为新键。

.NET列表和数组没有内置的相等比较,因此您需要提供自己的:

class ArrayEqComparer : IEqualityComparer<int[]> {

    public static readonly IEqualityComparer<int[]> Instance =
        new ArrayEqComparer();

    public bool Equals(int[] b1, int[] b2) {
        if (b2 == null && b1 == null)
           return true;
        else if (b1 == null | b2 == null)
           return false;
        return b1.SequenceEqual(b2);
    }

    public int GetHashCode(int[] a) {
        return a.Aggregate(37, (p, v) => 31*v + p);
    }
}
class ArrayEqComparer:IEqualityComparer{
公共静态只读IEqualityComparer实例=
新的ArrayQComparer();
公共布尔等于(int[]b1,int[]b2){
如果(b2==null&&b1==null)
返回true;
else if(b1==null | b2==null)
返回false;
返回b1.SequenceEqual(b2);
}
公共int GetHashCode(int[]a){
返回a.聚合(37,(p,v)=>31*v+p);
}
}
现在,您可以按如下方式构建词典:

var result = new Dictionary<int[],int>(ArrayEqComparer.Instance);
var result=newdictionary(ArrayEqComparer.Instance);

.NET列表和数组没有内置的相等比较,因此您需要提供自己的:

class ArrayEqComparer : IEqualityComparer<int[]> {

    public static readonly IEqualityComparer<int[]> Instance =
        new ArrayEqComparer();

    public bool Equals(int[] b1, int[] b2) {
        if (b2 == null && b1 == null)
           return true;
        else if (b1 == null | b2 == null)
           return false;
        return b1.SequenceEqual(b2);
    }

    public int GetHashCode(int[] a) {
        return a.Aggregate(37, (p, v) => 31*v + p);
    }
}
class ArrayEqComparer:IEqualityComparer{
公共静态只读IEqualityComparer实例=
新的ArrayQComparer();
公共布尔等于(int[]b1,int[]b2){
如果(b2==null&&b1==null)
返回true;
else if(b1==null | b2==null)
返回false;
返回b1.SequenceEqual(b2);
}
公共int GetHashCode(int[]a){
返回a.聚合(37,(p,v)=>31*v+p);
}
}
现在,您可以按如下方式构建词典:

var result = new Dictionary<int[],int>(ArrayEqComparer.Instance);
var result=newdictionary(ArrayEqComparer.Instance);

字典类允许自定义相等比较器作为字典比较器。通过使用Linq.Enumerable.SequenceEquals返回所有列表元素(0^first^second…)和Equals(IList x,IList y)的xor(运算符“^”),提供GetHashCode(IList obj),实现IEqualityComparer>。然后将其实例传递给Dictionary构造函数。

Dictionary类允许自定义相等比较器作为Dictionary比较器。通过使用Linq.Enumerable.SequenceEquals返回所有列表元素(0^first^second…)和Equals(IList x,IList y)的xor(运算符“^”),提供GetHashCode(IList obj),实现IEqualityComparer>。然后将其实例传递给字典构造函数。

默认相等是数组/列表本身的实例相等,而不是数据结构的内容。您正在传递两个具有相同内容的不同实例,这不会导致密钥冲突。在构造字典时,您可以传递自己的
IEqualityComperer
,该字典可以使用任何逻辑来比较键是否相等。默认相等是数组/列表本身的实例相等,而不是数据结构的内容。您正在传递两个具有相同内容的不同实例,这不会导致密钥冲突。在构建字典时,您可以传递自己的
IEqualityComperer
,该字典可以使用您希望比较键是否相等的任何逻辑。是否已有具有此行为的内置字典?还是在一个流行的库中?@joejag令我惊讶的是,没有一个内置的集合平等比较器,即使框架有足够的“管道”使它能够正常工作。我也不知道有哪个流行的库可以提供这种功能。只是出于好奇,为什么在
GetHasCode
中有37和31?@devuxer在查看了
String
中的
hashCode
的Java实现后,我开始乘以31。我或多或少随机选择了37作为另一个小素数。这显示了等式问题:Assert.IsTrue(new[]{1,1}==new[]{1,1});//False是否已经有这种行为的内置词典?还是在一个流行的库中?@joejag令我惊讶的是,没有一个内置的集合平等比较器,即使框架有足够的“管道”使它能够正常工作。我也不知道有哪个流行的库可以提供这种功能。只是出于好奇,为什么在
GetHasCode
中有37和31?@devuxer在查看了
String
中的
hashCode
的Java实现后,我开始乘以31。我或多或少随机选择了37作为另一个小素数。这显示了等式问题:Assert.IsTrue(new[]{1,1}==new[]{1,1});//假的