Контрольная сумма объектов в памяти - PullRequest
2 голосов
/ 18 января 2010

Допустим, у меня есть класс A, который наследуется от класса B в C #. У класса B есть свойство, называемое Checksum, которое при вызове во время выполнения предназначено для вычисления контрольной суммы всех свойств в экземпляре класса A (используемый алгоритм контрольной суммы особенно важен, вероятно, один из BCL).

Важно отметить, что алгоритм контрольной суммы должен игнорировать свойство контрольной суммы, в противном случае он потерпит неудачу при проверке позже (так как значение контрольной суммы будет изменено).

Итак, насколько я вижу, есть два варианта:

1) Переберите все открытые свойства объекта, используя отражение, объедините в строку и проверьте контрольную сумму.

2) Представьте, что объект представляет собой просто набор смежных адресов памяти, и обработайте его как байтовый массив и контрольную сумму.

1 - звучит медленно 2 - звучит сложно, так как я не уверен, как заставить его игнорировать строку, представляющую саму контрольную сумму, или как обрабатываются ссылки на другие объекты.

Есть ли у кого-нибудь идеи лучше, чем 1, который звучит как лучшее из этих двух решений?

Ответы [ 3 ]

5 голосов
/ 18 января 2010

Можно проверить свойство контрольной суммы как NonSerialized и сериализовать экземпляр класса в байтовый массив, а затем вычислить контрольную сумму. Таким образом, свойство будет игнорироваться при сериализации.

2 голосов
/ 18 января 2010

Почему это должна быть собственность?Если бы это был метод 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 - это long.Промежуточное значение (результат) умножается на 397 и помещается в мощность хэш-кода следующего компонента на каждом шаге.Непроверенный означает, что если целое число переполнено (что вероятно), то мы отбрасываем переполнение и оборачиваемся.Это должно дать разумное покрытие целочисленного пространства в большинстве случаев - хотя я бы порекомендовал протестировать покрытие, так как плохой хэш-код может иметь серьезные последствия для производительности вашей системы.

Следует соблюдать осторожность при обработке нулейлюбое поле, чтобы вы не умножали на ноль и не получали большое количество объектов с нулевым хеш-кодом.

1 голос
/ 18 января 2010

Вариант 3 заключается в создании метода «на лету», который вычисляет контрольную сумму всех свойств, например, с помощью отражения. Это неэффективно только для первого вызова, но сгенерированный метод может быть кэширован. Если вы знаете, какие типы должны быть проверены, вы также можете использовать генерацию кода для создания для них методов контрольной суммы во время компиляции.

...