简体   繁体   English

以类为键的 C# 字典

[英]C# Dictionary with a class as key

My question is basically the opposite of Dictionary.ContainsKey return False, but a want True and of "the given key was not present in the dictionary" error when using a self-defined class as key :我的问题基本上与Dictionary.ContainsKey 返回 False相反,但是当使用自定义类作为键时,想要 True并且“字典中不存在给定的键”错误
I want to use a medium-sized class as the dictionary's key, and the dictionary must compare the keys by reference, not by value equality.我想使用一个中等大小的类作为字典的键,并且字典必须通过引用而不是值相等来比较键。 The problem is, that the class already implements Equals() (which is performing value equality - which is what not what I want here).问题是,该类已经实现了Equals() (它正在执行值相等 - 这不是我在这里想要的)。

Here's a small test class for reproduction:这是一个用于复制的小型测试类:

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;
  }

}

I have NOT yet implemented GetHashCode() (actually I have, but it only returns base.GetHashCode() so far).我还没有实现GetHashCode() (实际上我已经实现了,但到目前为止它只返回base.GetHashCode() )。

Now I created a test program with a dictionary that uses instances of this class as keys.现在我创建了一个带有字典的测试程序,该字典使用此类的实例作为键。 I can add multiple identical instances to the dictionary without problems, but this only works because GetHashCode() returns different values:我可以毫无问题地向字典添加多个相同的实例,但这只是因为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
}

And the hash values are different every time, maybe because the calculatation in object.GetHashCode() uses some randomization or some numbers that come from the reference handle (which is different for each object).并且每次的哈希值都不同,可能是因为object.GetHashCode()的计算使用了一些随机化或一些来自引用句柄的数字(每个对象都不同)。
However, this answer on Why is it important to override GetHashCode when Equals method is overridden?但是,这个答案为什么在覆盖 Equals 方法时覆盖 GetHashCode 很重要? says that GetHashCode() must return the same values for equal objects, so I addedGetHashCode()必须为相等的对象返回相同的值,所以我添加了

  public override int GetHashCode ()
  {
    return m_iValue;
  }

After that, I could not add multiple equal objects to the dictionary any more.之后,我无法再向字典中添加多个相等的对象。

Now, there are two conclusions:现在,有两个结论:

  1. If I removed my own GetHashCode() again, the hash values will be different again and the dictionary can be used.如果我再次删除自己的GetHashCode() ,哈希值将再次不同,并且可以使用字典。 But there may be situations that accidentally give the same hash code for two equal objects, which will cause an exception at runtime, whose cause will for sure never be found.但是可能存在不小心给两个相等的对象赋予相同的哈希码的情况,这会在运行时导致异常,其原因肯定永远不会被找到。 Because of that (little, but not zero) risk, I cannot use a dictionary.由于这种(很小但不是零)风险,我不能使用字典。
  2. If I correctly implement GetHashCode() like I am supposed to do, I cannot use a dictionary anyway.如果我像我应该做的那样正确地实现了GetHashCode() ,无论如何我都不能使用字典。

What possibilities exist to still use a dictionary?仍然使用字典的可能性有多大?

Like many times before, I had the idea for a solution when writing this question.像以前很多次一样,我在写这个问题时就有了解决方案的想法。

You can specify an IEqualityComparer<TKey> in the constructor of the dictionary .您可以在字典构造函数中指定一个IEqualityComparer<TKey> There is one in the .net framework, but it's internal sealed , so you need to implement your own: .net 框架中有一个,但它是internal sealed ,因此您需要实现自己的:
Is there any kind of "ReferenceComparer" in .NET? .NET 中是否有任何类型的“ReferenceComparer”?

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);
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM