C# 未调用元组作为键GetHashCode的字典

C# 未调用元组作为键GetHashCode的字典,c#,dictionary,.net-core,hashtable,C#,Dictionary,.net Core,Hashtable,说明 正在尝试创建以元组为键的字典 但是,不会调用GetHashCode和Equals函数,因此会将重复的键添加到字典中 这是我想用作字典键的键类: class Key : IEqualityComparer<Tuple<int, int>> { private Tuple<int, int> _tuple; public Key(int a, int b) { _tuple

说明


正在尝试创建以元组为键的字典

但是,不会调用GetHashCode和Equals函数,因此会将重复的键添加到字典中

这是我想用作字典键的
类:

class Key : IEqualityComparer<Tuple<int, int>>
    {
        private Tuple<int, int> _tuple;

        public Key(int a, int b)
        {
            _tuple = new Tuple<int, int>(a, b);
        }


        public bool Equals(Tuple<int, int> x, Tuple<int, int> y)
        {
            return (x.Item1 == y.Item1 && x.Item2 == y.Item2);
        }

        public int GetHashCode(Tuple<int, int> obj)
        {
            return obj.Item1.GetHashCode() ^ obj.Item2.GetHashCode();
        }
    }
类密钥:IEqualityComparer
{
私有元组;
公钥(INTA、INTB)
{
_tuple=新的tuple(a,b);
}
公共布尔等于(元组x,元组y)
{
返回(x.Item1==y.Item1&&x.Item2==y.Item2);
}
public int GetHashCode(元组对象)
{
返回obj.Item1.GetHashCode()^obj.Item2.GetHashCode();
}
}
驱动程序代码:

public static void Main() {

    var map = new Dictionary<Key, int>();

    map.Add(new Key(1, 2), 3);
    map.Add(new Key(1, 2), 4); // <==== Should not add!
}
publicstaticvoidmain(){
var map=newdictionary();
地图添加(新键(1,2,3);

map.Add(新键(1,2,4);//您可以尝试以下解决方案

public class Key : IEquatable<Key>
{
    private Tuple<int, int> _tuple;

    public Key(int a, int b)
    {
        _tuple = new Tuple<int, int>(a, b);
    }

    public bool Equals(Key other)
    {
        return (this.GetHashCode() == other.GetHashCode());
    }

    public override int GetHashCode()
    {
        return _tuple.GetHashCode();
    }
}
公共类密钥:IEquatable
{
私有元组;
公钥(INTA、INTB)
{
_tuple=新的tuple(a,b);
}
公共布尔等于(关键其他)
{
返回(this.GetHashCode()==other.GetHashCode());
}
公共覆盖int GetHashCode()
{
返回_tuple.GetHashCode();
}
}

您可以尝试以下解决方案

public class Key : IEquatable<Key>
{
    private Tuple<int, int> _tuple;

    public Key(int a, int b)
    {
        _tuple = new Tuple<int, int>(a, b);
    }

    public bool Equals(Key other)
    {
        return (this.GetHashCode() == other.GetHashCode());
    }

    public override int GetHashCode()
    {
        return _tuple.GetHashCode();
    }
}
公共类密钥:IEquatable
{
私有元组;
公钥(INTA、INTB)
{
_tuple=新的tuple(a,b);
}
公共布尔等于(关键其他)
{
返回(this.GetHashCode()==other.GetHashCode());
}
公共覆盖int GetHashCode()
{
返回_tuple.GetHashCode();
}
}

另一种方法是使用
ValueTuple
作为键,默认情况下将根据其值进行比较

public static void Main() 
{
    var map = new Dictionary<(int, int), int>();

    map.Add((1, 2), 3);
    map.Add((1, 2), 4); // Throw an exception
}
publicstaticvoidmain()
{
var map=newdictionary();
地图添加((1,2,3);
Add((1,2,4);//引发异常
}
如果您想拥有自己的类来表示一个键,您只需创建
Tuple
的子类,并“免费”获得所需的行为

公共类密钥:元组
{
公钥(int item1,int item2):基(item1,item2)
{
}
}

另一种方法是使用
ValueTuple
作为键,默认情况下将根据其值进行比较

public static void Main() 
{
    var map = new Dictionary<(int, int), int>();

    map.Add((1, 2), 3);
    map.Add((1, 2), 4); // Throw an exception
}
publicstaticvoidmain()
{
var map=newdictionary();
地图添加((1,2,3);
Add((1,2,4);//引发异常
}
如果您想拥有自己的类来表示一个键,您只需创建
Tuple
的子类,并“免费”获得所需的行为

公共类密钥:元组
{
公钥(int item1,int item2):基(item1,item2)
{
}
}

如果要使用自己的类

    public class Key
    {
        public Key(int item1, int item2)
        {
            Tuple = new Tuple<int, int>(item1, item2);
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            if (obj is Key other)
            {
                return Tuple.Equals(other.Tuple);
            }

            return false;
        }

        public override int GetHashCode()
        {
            return Tuple.GetHashCode();
        }

        public Tuple<int, int> Tuple { get; private set; }
    }

    public void Do()
    {
        var map = new Dictionary<Key, int>();
        map.Add(new Key(1, 2), 3);
        map.Add(new Key(1, 2), 4); // will throw System.ArgumentException
    }

如果要使用自己的类

    public class Key
    {
        public Key(int item1, int item2)
        {
            Tuple = new Tuple<int, int>(item1, item2);
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            if (obj is Key other)
            {
                return Tuple.Equals(other.Tuple);
            }

            return false;
        }

        public override int GetHashCode()
        {
            return Tuple.GetHashCode();
        }

        public Tuple<int, int> Tuple { get; private set; }
    }

    public void Do()
    {
        var map = new Dictionary<Key, int>();
        map.Add(new Key(1, 2), 3);
        map.Add(new Key(1, 2), 4); // will throw System.ArgumentException
    }

问题是,在向字典添加项时,将调用默认的
Equals
GetHashCode
方法,它们使用引用比较来确定相等性

如果要覆盖此行为,则需要使用
override
关键字,并覆盖该方法:

class Key : IEquatable<Key>
{
    private readonly Tuple<int, int> tuple;

    public Key(int a, int b)
    {
        tuple = new Tuple<int, int>(a, b);
    }

    public bool Equals(Key other)
    {
        return other != null && 
            tuple.Item1 == other.tuple.Item1 && 
            tuple.Item2 == other.tuple.Item2;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as Key);
    }

    public override int GetHashCode()
    {
        return tuple.Item1.GetHashCode() ^ tuple.Item2.GetHashCode();
    }
}
类密钥:IEquatable
{
私有只读元组;
公钥(INTA、INTB)
{
tuple=新的tuple(a,b);
}
公共布尔等于(关键其他)
{
返回其他!=null&&
tuple.Item1==other.tuple.Item1&&
tuple.Item2==other.tuple.Item2;
}
公共覆盖布尔等于(对象对象对象)
{
返回等于(obj作为键);
}
公共覆盖int GetHashCode()
{
返回tuple.Item1.GetHashCode()^tuple.Item2.GetHashCode();
}
}

问题在于,在向字典添加项时,将调用默认的
Equals
GetHashCode
方法,它们使用引用比较来确定相等性

如果要覆盖此行为,则需要使用
override
关键字,并覆盖该方法:

class Key : IEquatable<Key>
{
    private readonly Tuple<int, int> tuple;

    public Key(int a, int b)
    {
        tuple = new Tuple<int, int>(a, b);
    }

    public bool Equals(Key other)
    {
        return other != null && 
            tuple.Item1 == other.tuple.Item1 && 
            tuple.Item2 == other.tuple.Item2;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as Key);
    }

    public override int GetHashCode()
    {
        return tuple.Item1.GetHashCode() ^ tuple.Item2.GetHashCode();
    }
}
类密钥:IEquatable
{
私有只读元组;
公钥(INTA、INTB)
{
tuple=新的tuple(a,b);
}
公共布尔等于(关键其他)
{
返回其他!=null&&
tuple.Item1==other.tuple.Item1&&
tuple.Item2==other.tuple.Item2;
}
公共覆盖布尔等于(对象对象对象)
{
返回等于(obj作为键);
}
公共覆盖int GetHashCode()
{
返回tuple.Item1.GetHashCode()^tuple.Item2.GetHashCode();
}
}
这里只发布了@Dmitri答案的简化版本作为参考

最简单的方法(无需安装额外的软件包)是不实现任何接口,只需覆盖
Equals
GetHashCode
方法,如下所示:

public class Key
{
    private readonly Tuple<int, int> _tuple;

    public Key(int item1, int item2)
    {
        _tuple = new Tuple<int, int>(item1, item2);
    }

    public override bool Equals(object obj)
    {
        var other = obj as Key;
        return _tuple.Item1 == other?._tuple.Item1 && _tuple.Item2 == other?._tuple.Item2;
    }

    public override int GetHashCode()
    {
        return _tuple.Item1.GetHashCode() ^ _tuple.Item2.GetHashCode();
    }

}
公共类密钥
{
私有只读元组u元组;
公钥(int项1、int项2)
{
_tuple=新的tuple(item1,item2);
}
公共覆盖布尔等于(对象对象对象)
{
var other=作为键的obj;
返回_tuple.Item1==other?_tuple.Item1&&u tuple.Item2==other?_tuple.Item2;
}
公共覆盖int GetHashCode()
{
返回_tuple.Item1.GetHashCode()^ _tuple.Item2.GetHashCode();
}
}
这里只发布了@Dmitri答案的简化版本作为参考

最简单的方法(无需安装额外的软件包)是不实现任何接口,只需覆盖
Equals
GetHashCode
方法,如下所示:

public class Key
{
    private readonly Tuple<int, int> _tuple;

    public Key(int item1, int item2)
    {
        _tuple = new Tuple<int, int>(item1, item2);
    }

    public override bool Equals(object obj)
    {
        var other = obj as Key;
        return _tuple.Item1 == other?._tuple.Item1 && _tuple.Item2 == other?._tuple.Item2;
    }

    public override int GetHashCode()
    {
        return _tuple.Item1.GetHashCode() ^ _tuple.Item2.GetHashCode();
    }

}
公共类密钥
{
私有只读元组u元组;
公钥(int项1、int项2)
{
_tuple=新的tuple(item1,item2);
}
公共覆盖布尔等于(对象对象对象)
{
var other=作为键的obj;
返回_tuple.Item1==other?_tuple.Item1&&u tuple.Item2==other?_tuple.Item2;
}
公共覆盖int GetHashCode()
{