简体   繁体   English

Dictionary.ContainsKey返回False,但想要True

[英]Dictionary.ContainsKey return False, but a want 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<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());
    }
}
}

What should I change to get true? 我应该改变什么才能成真?

You want true - but a and b are different objects. 你想要真实 - 但a和b是不同的对象。

You need to override GetHashCode and Equals on class Key 您需要在类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;
    }
}

It would probably help if you override Key.GetHashCode and Key.Equals. 如果你重写Key.GetHashCode和Key.Equals,它可能会有所帮助。

In Key : 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();
}

If you do not have the ability to override equality operators/Equals/GetHashCode as others have mentioned (as in, you do not control the source code of the object), you can provide an IEqualityComparer<Key> implementation in the constructor of the dictionary to perform your equality checks. 如果你没有能够像其他人提到的那样覆盖相等的运算符/ 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();
    }
}

As it stands, your Key is a reference object, so equality is only determined on reference unless you tell the world (or the dictionary) otherwise. 就目前而言,您的Key是一个引用对象,因此除非您告诉世界(或字典),否则仅在引用时确定相等性。

Overriding a class' GetHashCode and Equals methods so that it will work properly in a dictionary is not a very good approach. 覆盖类的GetHashCode和Equals方法以使其在字典中正常工作并不是一个非常好的方法。 The way a dictionary behaves should be an implementation detail of the dictionary, not of whatever class is being used as a key. 字典的行为方式应该是字典的实现细节,而不是用作键的任何类。 You'll get into trouble when you want to use the class in different dictionaries with different behavior. 当你想在具有不同行为的不同词典中使用该类时,你会遇到麻烦。 Or if you don't have access to the class source code. 或者,如果您无权访问类源代码。

A better mouse trap is to give the dictionary its own comparer. 一个更好的鼠标陷阱是给字典自己的比较器。 For example: 例如:

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

In order to use your own classes as dictionary keys, you should override GetHashCode and Equals. 要将您自己的类用作字典键,您应该重写GetHashCode和Equals。 Otherwise it will use the memory address to check for equality. 否则,它将使用内存地址来检查是否相等。

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

you problem is that 你的问题是

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

and

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

fix that and it should work I think. 解决这个问题,我觉得应该可行。 To fix it override the Equals method and check if the name values are the same. 要修复它,请覆盖Equals方法并检查名称值是否相同。 You should also override GetHashCode if you are overriding Equals. 如果要覆盖Equals,还应覆盖GetHashCode。

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

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

You need to override the Equals and GetHashCode methods of your Key class. 您需要覆盖Key类的EqualsGetHashCode方法。 In your case you could compare based on the key's name (or on any other unique property if your class is more complex). 在您的情况下,您可以根据键的名称进行比较(如果您的类更复杂,则可以在任何其他唯一属性上进行比较)。

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

1. Override Equals, Get Hash Code, and the '==' Operator. 1.覆盖等于,获取哈希代码和'=='运算符。

The Key class must override Equals in order for the Dictionary to detect if they are the same. Key类必须重写Equals ,以便Dictionary检测它们是否相同。 The default implementation is going to check references only. 默认实现仅检查引用。

Here: 这里:

        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. If Possible, use a struct. 2.如果可能,请使用结构。

You should use a struct for immutable datatypes like this, since they are passed by value. 您应该使用这样的不可变数据类型的结构,因为它们是按值传递的。 This would mean that you coulnd't accidentally munge two different values into the same key. 这意味着你不会意外地将两个不同的值混合到同一个键中。

Then you will need to override GetHashCode and Equals on the Key class. 然后,您需要在Key类上重写GetHashCode和Equals。

Without doing that, you get the default implementation of both. 如果不这样做,您将获得两者的默认实现。 Which results in the hashcode for a and b to be most likely not the same (I don't know how what the default implementation looks like), and a to be definitely not equal to b (the default Equals() implementation checks reference equality). 这导致a和b的哈希码很可能不一样(我不知道默认实现是怎么样的),而a肯定不等于b(默认的Equals()实现检查引用相等)。

In your case, assuming "name" is not a null, it could be implemented as 在您的情况下,假设“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);
        }
    }

Whether this is a satisfactory hash is a different story, but it shows the principle, nevertheless. 这是否是一个令人满意的哈希是一个不同的故事,但它显示了原则。

ContainsKey in this case is comparing Key as objects and checking to see if the objects themselves are the same -- they are not. 在这种情况下,ContainsKey将Key作为对象进行比较,并检查对象本身是否相同 - 它们不是。 You need to implement IComparable or override Key.Equals or something along those lines to get it to do what you want. 你需要实现IComparable或覆盖Key.Equals或类似的东西,以使它做你想要的。

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

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