Позволяет сказать, что у меня есть класс A, который наследуется от класса B в С#. Класс B имеет свойство на нем под названием Checksum, которое при вызове во время выполнения вычисляет контрольную сумму всех свойств экземпляра класса A (используемый алгоритм контрольной суммы particualr не важен, возможно, один из BCL).
Важно отметить, что алгоритм контрольной суммы должен игнорировать свойство контрольной суммы, иначе он будет терпеть неудачу после подтверждения позже (поскольку значение контрольной суммы будет изменено).
Итак, насколько я вижу, есть два варианта:
1) Итерация по всем общедоступным свойствам объекта с использованием отражения, конкатенация в строку и контрольную сумму, которая.
2) Представьте, что объект является просто связкой смежных адресов memeory и рассматривает это как массив байтов и контрольную сумму, которая.
1 - звучит медленно 2 - звучит сложно, так как я не уверен, как вы его проигнорируете строку, которая представляет собой контрольную сумму, или как обрабатываются ссылки на другие объекты.
Есть ли у кого-нибудь лучшие идеи, чем 1, который звучит лучше, чем эти два решения?
Вы можете украсить свойство контрольной суммы как NonSerialized
и сериализовать экземпляр класса в массив байтов, а затем вычислить контрольную сумму. Таким образом, свойство будет игнорироваться при сериализации.
Почему это должно быть свойство? Если бы это был метод, GetChecksum(), то вам не нужно было бы иметь какую-либо специальную логику, чтобы он не включал себя в расчет контрольной суммы. Теперь то, что вы создали, почти точно такое же, как и для существующего метода GetHashCode(), - просто предоставите реализацию этого.
Как правило, для каждого класса явным образом кодировал бы GetHashCode(), хотя быстрый веб-поиск будет показывать подходы, которые используют отражение, чтобы обеспечить общий (хотя и медленный) механизм. Обычно у каждого поля требуется включить в хэш-код, преобразовать его в целое число и умножить на фиксированное число, так что разные объекты с разными значениями полей дают разные хэш-коды, которые хорошо распределены по целочисленному диапазону.
В качестве примера Resharper генерирует методы GetHashCode(), которые выглядят следующим образом:
public override int GetHashCode()
{
unchecked
{
int result = a;
result = (result * 397) ^ (b != null ? b.GetHashCode() : 0);
result = (result * 397) ^ c.GetHashCode();
return result;
}
}
Где a - int, b - строка, а c - длинная. Промежуточное значение (результат) умножается на 397 и помещается в мощность следующего хэш-кода компонента на каждом шаге. Непроверенный означает, что если целое число переполнено (что вполне вероятно), мы отбрасываем переполнение и обертываем. В большинстве случаев это должно обеспечить разумное покрытие целочисленного пространства - хотя я бы рекомендовал тестировать покрытие, поскольку плохой хэш-код может иметь серьезные последствия для производительности вашей системы.
Следует соблюдать осторожность при обработке нулей любого поля, чтобы вы не умножались на ноль и заканчивали большим количеством объектов, все из которых имеют нулевой хеш-код.
Вариант 3 заключается в создании метода "на лету", который вычисляет контрольную сумму всех свойств, например. используя отражение .emit. Это неэффективно для первого вызова, но сгенерированный метод может быть кэширован. Если вы знаете, какие типы должны быть запрограммированы, вы также можете использовать генерацию кода для создания контрольных методов для них во время компиляции.