Почему HashSets с одинаковыми элементами возвращают разные значения при вызове GetHashCode ()? - PullRequest
0 голосов
/ 26 ноября 2018

Почему HashSet<T>.GetHashCode() возвращает разные хеш-коды, если они имеют одинаковые элементы?

Например:

[Fact]
public void EqualSetsHaveSameHashCodes()
{
    var set1 = new HashSet<int>(new [] { 1, 2, 3 } );
    var set2 = new HashSet<int>(new [] { 1, 2, 3 } );

    Assert.Equal(set1.GetHashCode(), set2.GetHashCode());
}

Этот тест не пройден.Почему?

Как получить нужный мне результат? «Равные множества дают одинаковый хэш-код»

Ответы [ 3 ]

0 голосов
/ 26 ноября 2018

По умолчанию (и если специально не задокументировано иное) ссылочные типы считаются равными, только если они ссылаются на один и тот же объект.Как разработчик, вы можете переопределить методы Equals () и GetHashCode (), чтобы объекты, которые вы считаете равными, возвращали true для Equals и то же самое int для GetHashCode.

В зависимости от используемой среды тестирования,будет либо CollectionAssert.AreEquivalent (), либо переопределение для Assert.Equal, которое принимает компаратор.

0 голосов
/ 26 ноября 2018

HashSet<T> по умолчанию не имеет семантики равенства значений.Он имеет семантику ссылочного равенства, поэтому два различных хеш-набора не будут равны или не будут иметь одинаковый хеш-код, даже если содержащиеся элементы одинаковы.

Вам нужно использовать специальную цель IEqualityComparer<HashSet<int>>, чтобы получитьповедение, которое вы хотите.Вы можете свернуть свой собственный или использовать тот, который по умолчанию предоставляет вам фреймворк:

var hashSetOfIntComparer = HashSet<int>.CreateSetComparer();

//will evaluate to true
var haveSameHash = hashSetOfIntComparer.GetHashCode(set1) ==
                   hashSetOfIntComparer.GetHashCode(set2);

Итак, если коротко, коротко:

Как я могу получить результат?необходимость? «Равные наборы дают одинаковый хэш-код»

Вы не можете этого сделать, если планируете использовать реализацию по умолчанию HashSet<T>.GetHashCode().Вы либо используете специальный компаратор, либо расширяете HashSet<T> и переопределяете Equals и GetHashCode в соответствии со своими потребностями.

0 голосов
/ 26 ноября 2018

Вы можете реализовать собственный HashSet, который переопределяет функцию GetHashCode, которая генерирует новый хэш-код из всего содержимого, как показано ниже:

public class HashSetWithGetHashCode<T> : HashSet<T>
{
    public override int GetHashCode()
    {
        unchecked // Overflow is fine, just wrap
        {
            int hash = 17;
            foreach (var item in this)
                hash = hash * 23 + item.GetHashCode();
            return hash;
        }
    }
}
...