ContainsKey в словаре hashset<myClass>

У меня есть словарь:

Dictionary<HashSet<myClass>, List<MyObj>> myDict = ...

И я имею:

HashSet<myClass> myHashSet = ...

Я хочу проверить, содержит ли словарь (myDict) myHashSet.

Я попытался переопределить два метода:

1) равный

2) GetHashCode

public class myClass
{
    public string id;
    public int number;

    public override bool Equals(object obj)
    {
        myClass other = obj as myClass;
        bool ret = false;
        if (other != null)
        {
            ret = (this.number == other.number) && (this.id == other.id);
        }
        return ret;
    }

    public override int GetHashCode()
    {
        return this.number ^ this.id.GetHashCode();
    }
};

К сожалению, ключ, найденный в словаре, возвращает false для кода:myDict.ContainsKey(myHashSet)

Любая помощь приветствуется!

2 ответа

Просто потому, что ты переиграл myClass "s Equals( а также GetHashCode() это не значит что ты переиграл HashSet<myClass> "s Equals( а также GetHashCode() это то, что используется при поиске в словаре.

Если вы хотите, чтобы это работало, вам нужно пройти IEqualityComparer<HashSet<myClass>> в конструктор словаря, чтобы он использовал этот компаратор при поиске в словаре.

public class myClassSetComperer : IEqualityComparer<HashSet<myClass>>
{
    public bool Equals(HashSet<myClass> x, HashSet<myClass> y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (ReferenceEquals(null, x)) return false;
        if (ReferenceEquals(null, y)) return false;
        return x.SetEquals(y);
    }

    public int GetHashCode(HashSet<myClass> obj)
    {
        unchecked
        {
            int x = 0;
            foreach (var myClass in obj)
            {
                x = (x*397) ^ myClass?.GetHashCode() ?? 0;
            }
            return x;
        }
    }
}

//elsewhere
Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>, List<MyObj>>(new myClassSetComperer());

ОЧЕНЬ ВАЖНОЕ ПРИМЕЧАНИЕ: словарные ключи (и хэш-наборы) ужасно ломаются, если вы делаете что-либо, что вызывает Equals( или же GetHashCode() изменить один раз, вставив в качестве ключа поиска. Если вы измените HashSet<myClass> или один из myClass Объекты после того, как вы поместите его в словарь, вы сломаете словарь и, возможно, HashSet. Посмотрите этот очень хороший пост Эрика Липперта в блоге "Руководства и правила для GetHashCode"

Переопределение GetHasCode и Equal происходит при сравнении экземпляров myClass.

Вот пример использования ContainsKey, который проверяется по ссылке на объекты.

Dictionary<HashSet<string>, List<string>> hashSetDictionary = new Dictionary<HashSet<string>, List<string>>();
            var myHashSet = new HashSet<string>();

            hashSetDictionary.Add(myHashSet, null);
            Console.WriteLine(hashSetDictionary.ContainsKey(myHashSet));

Вот обновление вашего кода

 public class myClass
    {
        public myClass(string text, int num)
        {
            this.Text = text;
            this.Num = num;
        }

        public string Text { get; set; }
        public int Num { get; set; }
    }

    public class MyObj { }

    public class AlwaysTrueHashSet<T> : HashSet<T>
    {
        public override bool Equals(object obj)
        {
            return this.GetHashCode() == obj.GetHashCode();
        }

        public override int GetHashCode()
        {
            return "Counting hashcode".GetHashCode();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {


            Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>,


            List<MyObj>>();
            var myHashSet1 = new AlwaysTrueHashSet<myClass>();
            myHashSet1.Add(new myClass("123", 5));
            myDict.Add(myHashSet1, null);



            var myHashSet2 = new AlwaysTrueHashSet<myClass>();
            myHashSet2.Add(new myClass("123", 5));

            /*
             * when containsKey is invoked, it's checking if the reference of myHashSet2 is the same as myHashSet1.
             * That's the default behavior.
             * 
             * extend HashSet, and override the gethashcode and equal methods  
             */
            if (myDict.ContainsKey(myHashSet2))
            {
                Console.WriteLine("in");
                int i = 3; // it doesn't get this line }  
            }
        }
    }
Другие вопросы по тегам