IComparable 是在字典中强制使用唯一键的最佳方式吗?

Is IComparable the best way to use to enforce unique keys in Dictionary?

我有一个 class MyClass,我想将它作为字典的键,如下所示:

Dictionary<MyClass, string> dict = new Dictionary<MyClass, string>();

我想保证MyClass是唯一键,唯一性是通过查看MyClass.UniqueProperty指定的。我的第一个想法是重载 == 运算符,但我发现 C# 不允许这样做。然后我找到了 IComparable 接口。这会成功吗?或者我应该重载 Object.Equals(obj)?

Is IComparable the best way to use to enforce unique keys in Dictionary?

否 - IComparable 用于查看一个对象是否大于、等于或小于另一个对象。它主要用于排序例程。它可以用来判断两个对象是否相等,但它不是"best"方式。

Or should I overload Object.Equals(obj)?

是的。您还可以实现 IEquatable<T>,如果您已经适当地覆盖了 Equals(和 GetHashCode),这通常是微不足道的。

请注意,如果您将对象用作散列键,则 GetHashCode 的实现至关重要。需要遵循 many guidelines 来实现正确的散列例程,而且只比较相等性比较棘手。

My first thought was to overload the == operator, but I found that C# does not allow this.

嗯,你可以,但它不适合你正在做的事情。 == 运算符通常用于 reference 相等,意思是 "do these two variables point to the same instance"Object.Equals更适合value相等,意思是"are these two objects really describing the same thing"

词典已为自定义平等规则做好了充分准备。这就是为什么它有一个构造函数需要 IEqualityComparer (https://msdn.microsoft.com/en-us/library/ms132072(v=vs.110).aspx).

由于您只关心字典上下文中的相等性,IEqualityComparer<MyClass> 是最直接的解决方案。

原始示例:

void Main()
{
  var dict = new Dictionary<MyClass, string>(new MyClassUniqueIdEqualityComparer());

  dict.Add(new UserQuery.MyClass { UniqueId = 1 }, "Hi!");

  dict.ContainsKey(new UserQuery.MyClass { UniqueId = 2 }).Dump(); // False
  dict.ContainsKey(new UserQuery.MyClass { UniqueId = 1 }).Dump(); // True
}

public class MyClass
{
  public int UniqueId { get; set; }
}

public class MyClassUniqueIdEqualityComparer : IEqualityComparer<MyClass>
{
  public bool Equals(MyClass a, MyClass b) 
  {
    return a.UniqueId == b.UniqueId;
  }

  public int GetHashCode(MyClass a)
  {
    return a.UniqueId.GetHashCode();
  }
}

主要好处是相等规则仅适用于相等比较器定义的情况。您不必确保例如之间的适当平等。派生的 class 和基础的 class - 这一切都在字典和比较器的约定之内。由于 EqualsGetHashCode 方法对于字典而言不是虚拟的,因此它们甚至允许不同类型之间的相等性,只要它们实现相同的接口——这是你真的不想做的object.EqualsIEquatable<T>IComparable<T>.