【问题标题】:C# Dictionary with a class as key以类为键的 C# 字典
【发布时间】:2019-07-14 09:32:59
【问题描述】:

我的问题基本上与Dictionary.ContainsKey return False, but a want True"the given key was not present in the dictionary" error when using a self-defined class as key相反:
我想使用一个中等大小的类作为字典的键,字典必须通过引用来比较键,而不是值相等。问题是,该类已经实现了Equals()(它正在执行值相等——这不是我想要的)。

这是一个用于重现的小型测试类:

class CTest
{
  public int m_iValue;

  public CTest (int i_iValue)
  {
    m_iValue = i_iValue;
  }

  public override bool Equals (object i_value)
  {
    if (ReferenceEquals (null, i_value))
      return false;
    if (ReferenceEquals (this, i_value))
      return true;

    if (i_value.GetType () != GetType ())
      return false;

    return m_iValue == ((CTest)i_value).m_iValue;
  }

}

我还没有实现GetHashCode()(实际上我已经实现了,但到目前为止它只返回base.GetHashCode())。

现在我创建了一个带有字典的测试程序,该字典使用此类的实例作为键。我可以毫无问题地将多个相同的实例添加到字典中,但这仅适用于 GetHashCode() 返回不同的值:

private static void Main ()
{
  var oTest1 = new CTest (1);
  var oTest2 = new CTest (1);
  bool bEquals = Equals (oTest1, oTest2);   // true
  var dict = new Dictionary<CTest, int> ();
  dict.Add (oTest1, 1);
  dict.Add (oTest2, 2);         // works
  var iValue1 = dict[oTest1];   // correctly returns 1
  var iValue2 = dict[oTest2];   // correctly returns 2
  int iH1 = oTest1.GetHashCode ();   // values different on each execution
  int iH2 = oTest2.GetHashCode ();   // values different on each execution, but never equals iH1
}

而且哈希值每次都不同,可能是因为object.GetHashCode() 中的计算使用了一些随机化或来自参考句柄的一些数字(每个对象都不同)。
但是,Why is it important to override GetHashCode when Equals method is overridden? 上的 this answerGetHashCode() 必须为相等的对象返回相同的值,所以我添加了

  public override int GetHashCode ()
  {
    return m_iValue;
  }

在那之后,我不能再向字典中添加多个相等的对象了。

现在,有两个结论:

  1. 如果我再次删除我自己的GetHashCode(),哈希值将再次不同,并且可以使用字典。但是可能会出现意外给两个相等的对象给出相同的哈希码的情况,这会在运行时导致异常,其原因肯定永远找不到。由于那个(很小,但不是零)风险,我不能使用字典。
  2. 如果我按照我应该做的那样正确实现GetHashCode(),我无论如何都不能使用字典。

还有哪些可能仍然使用字典?

【问题讨论】:

  • 您可以通过在对象之间使用分隔符来获得重复的哈希值。例如,如果 x = hash(a)、y = hash(b) 和 xy = hash(c)。所以你有 xy = hash(a) + hash(b) = hash(c)。所以为了防止重复使用像'^'这样的分隔符所以哈希x^y = hash(a) + hash(b) while xy = hash(c)。

标签: c# class dictionary key


【解决方案1】:

像以前一样,在写这个问题时,我有一个解决方案的想法。

您可以在constructor of the dictionary 中指定IEqualityComparer&lt;TKey&gt;。 .net框架里有一个,不过是internal sealed,所以需要自己实现:
Is there any kind of "ReferenceComparer" in .NET?

internal class ReferenceComparer<T> : IEqualityComparer<T> where T : class
{
  static ReferenceComparer ()
  {
    Instance = new ReferenceComparer<T> ();
  }

  public static ReferenceComparer<T> Instance { get; }

  public bool Equals (T x, T y)
  {
    return ReferenceEquals (x, y);
  }

  public int GetHashCode (T obj)
  {
    return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode (obj);
  }
}

【讨论】:

    猜你喜欢
    • 2018-02-11
    • 2022-01-11
    • 1970-01-01
    • 2015-09-03
    • 1970-01-01
    • 2017-05-06
    • 2013-12-03
    • 2017-04-25
    • 1970-01-01
    相关资源
    最近更新 更多