У меня проблема с получением уникального идентификатора int32 с этими свойствами:
- Он должен быть всегда одинаковым для одних и тех же объектов в текущем экземпляре программы.
- Он всегда должен отличаться в текущем экземпляре программы для разных объектов, чтобы не было никаких коллизий.
Мне нужен этот уникальный идентификатор для сравнения сложных объектов и работы с такими классами, как Dictionary‹> или HashSet‹> и т. д.
Я бы очень хотел избежать использования каких-либо хеш-таблиц или предварительных вычислений любого рода, а вместо этого иметь алгоритм, который будет делать это на лету, чтобы исключить внешние зависимости и упростить модульное тестирование.
Псевдокод объекта:
class ComplexObject
{
public readonly FirstEnum First; // ~50 different values
public readonly IFirstModificator FirstModificator; // 4 implementations x 15 values (~60 values total)
public readonly InternalObject[] Internal; //1-10 values in array
}
class InternalObject
{
public readonly SecondEnum Second; // ~30 different values
public readonly SecondModificator SecondModificator; // ~15 different values
}
Если это важно, моя доменная модель содержит около 100 000 уникальных объектов типа ComplexObject.
Я уже пробовал:
- Сериализация объекта в json и получение хэша этой строки (используя метод string.GetHashCode()). Он создает коллизии даже в текущем экземпляре программы.
- Подобный код также вызывает много коллизий:
unchecked
{
int hash = 17;
hash = hash * 31 + firstField.GetHashCode();
hash = hash * 31 + secondField.GetHashCode();
return hash;
}
unchecked
{
int hash = (int) 17;
hash = (hash * 31) ^ field1.GetHashCode();
hash = (hash * 31) ^ field2.GetHashCode();
return hash;
}
ОБНОВЛЕНО:
IFirstModificator имеет разные реализации, но в целом выглядит так:
class FirstModificator : IFirstModificator
{
public int Value {get;set;} //~15 values
}
Остальные параметры реализации IFrstModificator влияют\применяются (не уверен, что мой английский понятен) только на обработку данных.
class SecondModificator
{
public int Value {get;set;} //~15 values
}
Внешний интерфейс и данные, необходимые для создания экземпляра класса, аналогичны реализации IFrstModificator, но на самом деле это разные классы.
Int32
имеет всего 32 бита для игры, и этого просто недостаточно, чтобы гарантировать хеширование без коллизий для такого количества объектов (при условии, что вы не можете использовать какие-либо специальные свойства распределения значений). Обратите внимание, однако, что хеширование без коллизий не требуется для правильного использования таких классов, какDictionary
; коллизия просто означает, что производительность будет немного меньше, поскольку несколько объектов будут занимать одно и то же ведро. Поиск в списке 2 или 3 столкнувшихся объектов не намного медленнее, чем просто выборка одного. - person Jeroen Mostert   schedule 19.06.2020InternalObject
, сопоставив все значенияSecondModificator
с 0-15 иSecond
с 0-30, затем выполнитеSecondModificator * 16 + Second
). Конечно, это может быть намного сложнее, чем просто общий хэш. - person Jeroen Mostert   schedule 19.06.2020Int64
будет достаточно) , сохраняя его вместе с вашим объектом (или отдельнымConditionalWeakTable
) и проверяя его на совпадение, прежде чем выполнять полное сравнение на равенство. Однако ваши объекты не кажутся достаточно большими, чтобы гарантировать это, занимая не более нескольких байтов. Столкновения должны стать очень серьезными, прежде чем это действительно станет проблемой. - person Jeroen Mostert   schedule 19.06.2020IFirstModificator
иSecondModificator
и их реализации? Кроме того, что составляет идентичность для объекта? Возможно ли иметь повторяющиеся объектыInternalObject
или повторяющиеся объектыComplexObject
, которые должны рассматриваться как разные? - person NetMage   schedule 20.06.2020HashCode
целей. - person NetMage   schedule 23.06.2020InternalObject
? Должен ли хэш-код отражать, находятся ли они в другом порядке в двухComplexObject
? - person NetMage   schedule 30.06.2020