【问题标题】:What comparer should I use for a .NET Dictionary to use the EqualityComparer<T> methods of the Key?我应该为 .NET 字典使用什么比较器来使用密钥的 EqualityComparer<T> 方法?
【发布时间】:2019-11-14 01:22:43
【问题描述】:

我的Position 类派生自EqualityComparer&lt;T&gt; 类。我希望字典使用覆盖的方法,但它使用的是Object.EqualsObject.GetHashCode 中的方法。我应该为Dictionary 使用什么比较器来使用Position 类的EqualityComparer&lt;T&gt; 方法?

using System.Collections.Generic;
using System.Diagnostics;

namespace ConsoleApp1
{
    class Position : EqualityComparer<Position>
    {
        public int X { get; set; }
        public int Y { get; set; }

        public override bool Equals(Position left, Position right)
        {
            if (left == null || right == null)
                return false;

            return left.X == right.X && left.Y == right.Y;
        }

        public override int GetHashCode(Position cell)
        {
            if (cell == null)
                return 0;

            return cell.X * 31 + cell.Y;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var dictionary = new Dictionary<Position, int>();
            var position = new Position();
            position.X = 1;
            position.Y = 1;
            dictionary[position] = 1;
            position = new Position();
            position.X = 1;
            position.Y = 1;
            var found = dictionary.TryGetValue(position, out var result);
            Debug.Assert(found);
            Debug.Assert(result == 1);
        }
    }
}

【问题讨论】:

  • "我的 Position 类派生自 EquailityComparer 类。" - 你到底希望那里发生什么?比较器是比较其他一些对象…可能你把它和Equatable&lt;T&gt;混合了…可能这个stackoverflow.com/questions/25853384/…澄清了一些…
  • @AlexeiLevenkov 我希望 Dictionary 调用 Position.GetHashCode(Position cell) 来获取 Position 类的哈希码并调用 Position.Equals(Position left, Position right) 来确定 Position 类是否为是否与字典中的相同
  • 它的相等性由 Object.Equals (非静态的)检查。如果要更改这些规则,请覆盖该函数 |比较器是关于找到两个事物的相对位置。他们通过返回一个 int 来做到这一点。有两个比较器:默认比较器和显式比较器。 | ICombarable&lt;T&gt; 是默认比较器。然而,它的功能变得很难定义,一旦你得到超过 1 个字段 - X 的值是否高于 Y? |显式比较器类似于IComparer&lt;T&gt;。但是在 LINQ 或委托中,lambda 表达式也是一回事。

标签: c# .net dictionary


【解决方案1】:

虽然在对象本身上实现比较器是非常awkward不寻常的,但您只需将比较器的实例传递给Dictionary 构造函数,如EqualityComparer 示例所示。

var dictionary = new Dictionary<Position, int>(new Position());

更常见的做法是

  • 为比较器使用单独的类(如果您需要多个比较变体) - 在类型本身上使用类型为 EqualsGetHashCode 实现 IEquatable&lt;T&gt;(如果在您的情况下存在自然相等)。在值类型的情况下,这比 object.Equals 方法更可取,因为 Equals(object) 强制对值类型进行装箱。
  • 只需实现object.Equalsobject.GetHashCode,如John 的answer 所示 - 如果您的类型具有自然平等并且它是引用类型 (class),这是最直接的方法。

【讨论】:

  • 知道了。我同意,这个逻辑应该是单独的类。
  • @RM 我已经更新了答案,因此它可能会解决您在 cmets 中遇到的所有问题(包括奇怪的“避免拳击”评论)。
【解决方案2】:

替代答案:您可以覆盖 PositionGetHashCodeEquals 方法:

class Position
{
    public int X { get; set; }
    public int Y { get; set; }

    public override bool Equals(object other)
    {
        if (other == null || !(other is Position))
        {
            return false;
        }
        var otherPosition = (Position)other;
        return otherPosition.X == this.X && otherPosition.Y == this.Y;
    }

    public override int GetHashCode()
    {
        return this.X * 31 + this.Y;
    }
}

这样你就可以像这样简单地声明你的字典:

var dict = new Dictionary<Position, string>();

它会按照你的预期工作。

Try it online

【讨论】:

  • 请注意,这正是他们想要避免的 OP 认为 - Equals(object) 需要装箱 struct... 但 OP 有 class Position - 所以有不是拳击。
猜你喜欢
  • 1970-01-01
  • 2011-03-24
  • 2016-04-17
  • 1970-01-01
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多