Dictionary.ContainsKey返回False,但想要True

时间:2010-06-10 13:44:50

标签: c# .net dictionary

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<Key, int> d = new System.Collections.Generic.Dictionary<Key, int>();
        d.Add(a, 1);
        return d.ContainsKey(b).ToString();
    }

    static void Main(string[] args)
    {
        System.Console.WriteLine(Test());
    }
}
}

我应该改变什么来实现?

12 个答案:

答案 0 :(得分:35)

你想要真实 - 但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;
    }
}

答案 1 :(得分:8)

如果你覆盖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();
}

答案 2 :(得分:6)

如果你没有能力像其他人提到的那样覆盖相等的运算符/ Equals / GetHashCode(例如,你没有控制对象的源代码),你可以提供IEqualityComparer<Key>实现。字典的构造函数,用于执行相等性检查。

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

    public int GetHashCode(Key obj)
    {
        return obj.Name.GetHashCode();
    }
}

就目前而言,你的Key是一个引用对象,所以除非你告诉世界(或字典),否则只能在引用时确定相等。

答案 3 :(得分:4)

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

更好的鼠标陷阱是为字典提供自己的比较器。例如:

using System;
using System.Collections.Generic;

class Program {
    static void Main(string[] args) {
        var d = new Dictionary<Key, int>(new MyComparer());
        d.Add(new Key("A"), 1);
        Console.WriteLine(d.ContainsKey(new Key("a")));
        Console.ReadLine();
    }
    private class MyComparer : IEqualityComparer<Key> {
        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; }
    }
}

答案 4 :(得分:2)

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

    public class Key
    {
        string name;
        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( other == null )
                return false;

            return name == other.name;
        }
    }

答案 5 :(得分:1)

你的问题是那个

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

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

解决这个问题,我觉得应该可行。要修复它,请覆盖Equals方法并检查名称值是否相同。如果要覆盖Equals,还应该覆盖GetHashCode。

答案 6 :(得分:1)

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

答案 7 :(得分:0)

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

答案 8 :(得分:0)

您需要覆盖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();
    }
}

答案 9 :(得分:0)

<强> 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。如果可能,请使用结构。

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

答案 10 :(得分:0)

然后你需要在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);
        }
    }

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

答案 11 :(得分:-1)

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