Dictionary.ContainsKey返回False,但想要True

namespace Dic { public class Key { string name; public Key(string n) { name = n; } } class Program { static string Test() { Key a = new Key("A"); Key b = new Key("A"); System.Collections.Generic.Dictionary d = new System.Collections.Generic.Dictionary(); d.Add(a, 1); return d.ContainsKey(b).ToString(); } static void Main(string[] args) { System.Console.WriteLine(Test()); } } } 

我应该改变什么才能成真?

你想要真实 – 但a和b是不同的对象。

您需要在类Key上覆盖GetHashCode和Equals

 public class Key { string name; public Key(string n) { name = n; } public override int GetHashCode() { if (name == null) return 0; return name.GetHashCode(); } public override bool Equals(object obj) { Key other = obj as key; return other != null && other.name == this.name; } } 

如果你覆盖Key.GetHashCode和Key.Equals,它可能会有所帮助。

Key

 public override bool Equals(object obj) { var k = obj as Key; if (k != null) { return this.name == k.name; } return base.Equals(obj); } public override int GetHashCode() { return this.name.GetHashCode(); } 

如果你没有能够像其他人提到的那样覆盖相等的运算符/ Equals / GetHashCode(如你所知,你不控制对象的源代码),你可以在字典的构造函数中提供IEqualityComparer实现。执行你的平等检查。

 class KeyComparer : IEqualityComparer { public bool Equals(Key x, Key y) { return x.Name == y.Name; } public int GetHashCode(Key obj) { return obj.Name.GetHashCode(); } } 

就目前而言,您的Key是一个引用对象,因此除非您告诉世界(或字典),否则仅在引用时确定相等性。

覆盖类的GetHashCode和Equals方法以使其在字典中正常工作并不是一个非常好的方法。 字典的行为方式应该是字典的实现细节,而不是用作键的任何类。 当你想在具有不同行为的不同词典中使用该类时,你会遇到麻烦。 或者,如果您无权访问类源代码。

一个更好的鼠标陷阱是给字典自己的比较器。 例如:

 using System; using System.Collections.Generic; class Program { static void Main(string[] args) { var d = new Dictionary(new MyComparer()); d.Add(new Key("A"), 1); Console.WriteLine(d.ContainsKey(new Key("a"))); Console.ReadLine(); } private class MyComparer : IEqualityComparer { public bool Equals(Key x, Key y) { return string.Compare(x.Name, y.Name, true) == 0; } public int GetHashCode(Key obj) { return obj.Name.ToUpper().GetHashCode(); } } public class Key { public string Name { get; set; } public Key(string name) { Name = name; } } } 

要将您自己的类用作字典键,您应该重写GetHashCode和Equals。 否则,它将使用内存地址来检查是否相等。

    公共课钥匙
     {
        字符串名称;
         public Key(string n){name = n;  }

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

         public override bool Equals(object obj)
         {
             var other = obj as Key;
             if(其他== null)
                返回虚假;

             return name == other.name;
         }
     }

您需要覆盖Key类的Equals和GetHashCode方法。

你的问题是

 new Key("A").Equals(new Key("A"))==false. 

 new Key("A").GetHashCode()!=new Key("A").GetHashCode() 

修复它,它应该工作,我想。 要修复它,请覆盖Equals方法并检查名称值是否相同。 如果要覆盖Equals,还应覆盖GetHashCode。

它们内部具有相同的值但是!= b,因为它们是2个不同的变量。

您需要覆盖Key类的EqualsGetHashCode方法。 在您的情况下,您可以根据键的名称进行比较(如果您的类更复杂,则可以在任何其他唯一属性上进行比较)。

 public class Key { string name; public Key(string n) { name = n; } public override bool Equals(object obj) { Key k = obj as Key; if (k == null) return false; return name.Equals(k.name); } public override int GetHashCode() { return name.GetHashCode(); } } 

然后,您需要在Key类上覆盖GetHashCode和Equals。

如果不这样做,您将获得两者的默认实现。 这导致a和b的哈希码很可能不一样(我不知道默认实现是怎么样的),而a肯定不等于b(默认的Equals()实现检查引用相等)。

在您的情况下,假设“name”不是null,它可以实现为

  public class Key { string name; public override int GetHashCode() { return name.GetHashCode(); } public override bool Equals(object obj) { if (obj == null) { return false; } Key objAsKey = obj as Key; if (objAsKey == null) { return false; } return this.name.Equals(objAsKey.Name); } } 

这是否是一个令人满意的哈希是一个不同的故事,但它显示了原则。

1.覆盖等于,获取哈希代码和’==’运算符。

Key类必须重写Equals ,以便Dictionary检测它们是否相同。 默认实现仅检查引用。

这里:

  public bool Equals(Key other) { return this == other; } public override bool Equals(object obj) { if (obj == null || !(obj is Key)) { return false; } return this.Equals((Key)obj); } public static bool operator ==(Key k1, Key k2) { if (object.ReferenceEquals(k1, k2)) { return true; } if ((object)k1 == null || (object)k2 == null) { return false; } return k1.name == k2.name; } public static bool operator !=(Key k1, Key k2) { if (object.ReferenceEquals(k1, k2)) { return false; } if ((object)k1 == null || (object)k2 == null) { return true; } return k1.name != k2.name; } public override int GetHashCode() { return this.name == null ? 0 : this.name.GetHashCode(); } 

2.如果可能,请使用结构。

您应该使用这样的不可变数据类型的结构,因为它们是按值传递的。 这意味着你不会意外地将两个不同的值混合到同一个键中。

在这种情况下,ContainsKey将Key作为对象进行比较,并检查对象本身是否相同 – 它们不是。 你需要实现IComparable或覆盖Key.Equals或类似的东西,以使它做你想要的。