Dictionary.ContainsKey return False, but a want True

前端 未结 12 903
野性不改
野性不改 2020-12-03 10:16
namespace Dic
{
public class Key
{
    string name;
    public Key(string n) { name = n; }
}

class Program
{
    static string Test()
    {
        Key a = new Key(         


        
相关标签:
12条回答
  • 2020-12-03 11:14

    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.

    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.

    0 讨论(0)
  • 2020-12-03 11:19

    1. Override Equals, Get Hash Code, and the '==' Operator.

    The Key class must override Equals in order for the Dictionary to detect if they are the same. 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.

    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.

    0 讨论(0)
  • 2020-12-03 11:20

    In order to use your own classes as dictionary keys, you should override GetHashCode and 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;
            }
        }
    
    
    0 讨论(0)
  • 2020-12-03 11:21

    You want true - but a and b are different objects.

    You need to override GetHashCode and Equals on class Key

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-03 11:23

    Overriding a class' GetHashCode and Equals methods so that it will work properly in a dictionary is not a very good approach. 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; }
        }
    }
    
    0 讨论(0)
  • 2020-12-03 11:23

    you need to override Equals and GetHashCode methods of your Key class.

    0 讨论(0)
提交回复
热议问题