В .NET 4.0, какова реализация по умолчанию Equals для типов значений? - PullRequest
27 голосов
/ 29 ноября 2011

Кажется, что две страницы документации противоречат этой теме:

  • Метод ValueType.Equals говорит "Реализация по умолчанию метода Equals использует отражение для сравнения соответствующих полей obj и этого экземпляра."
  • Метод Object.Equals (Object) говорит: «Реализация по умолчанию Equals поддерживает равенство ссылок для ссылочных типов и битовое равенство для типов значений

Так это побитовое равенство или отражение?

Я взглянул на исходный код ValueType и нашел комментарий со словами

// если в этом объекте нет ссылок GC, мы можем избежать отражения

// и сделать быстрый memcmp

Может кто-нибудь уточнить, что означает "ссылка на GC"? Я предполагаю, что это поле имеет ссылочный тип, но я не уверен.

Если я создам struct, который имеет только поля типа значения, будут ли всегда сравниваться его экземпляры?

ОБНОВЛЕНИЕ: Документация для .Net 4.5 была значительно улучшена: она свободна от упомянутого противоречия и теперь дает лучшее понимание того, как работает проверка на равенство типов значений по умолчанию.

Ответы [ 2 ]

43 голосов
/ 29 ноября 2011

System.ValueType.Equals специально.Он выполняет следующие шаги по порядку, пока не получит некоторый результат:

  1. Если obj по сравнению с 'null', он возвращает false.
  2. Еслиthis и obj аргументы разных типов, он возвращает false.
  3. Если тип "blittable", он сравнивает образы памяти.Если они идентичны, возвращается true.
  4. Наконец, он использует отражение для вызова Equals парных экземпляров полей для каждого значения.Если какое-либо из этих полей не равно, возвращается false.В противном случае возвращается true.Обратите внимание, что он никогда не вызывает базовый метод, Object.Equals.

Поскольку он использует отражение для сравнения полей, вы должны всегда переопределять Equalsна любом ValueType, который вы создаете.Отражение медленное.

Когда это "GCReference" или поле в структуре, являющееся ссылочным типом, оно заканчивается использованием отражения в каждом поле для сравнения.Это необходимо сделать, потому что struct на самом деле имеет указатель на расположение ссылочного типа в куче.

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

Для структуры только с типами значений для полей, т.е. структуры только с одним int поле, отражение не производится во время сравнения.Ни одно из полей не ссылается на что-либо в куче, поэтому нет GCReference или GCHandle.Кроме того, любой экземпляр этой структуры будет иметь одинаковую структуру полей в памяти (с некоторыми небольшими исключениями), поэтому команда CLR может выполнить прямое сравнение памяти (memcmp), которое намного быстрее, чем другой параметр.

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

Этот не означает, что вы должны использовать реализацию по умолчанию Equals.На самом деле, не делай этого.Останови это.Он выполняет сравнение битов, которые не всегда точны.Что это вы говорите?Позвольте мне показать вам:

private struct MyThing
{
    public float MyFloat;
}

private static void Main(string[] args)
{
    MyThing f, s;
    f.MyFloat = 0.0f;
    s.MyFloat = -0.0f;

    Console.WriteLine(f.Equals(s));  // prints False
    Console.WriteLine(0.0f == -0.0f); // prints True
}

Числа математически равны, но они не равны в своем двоичном представлении.Итак, еще раз подчеркну, не полагаться на реализацию по умолчанию ValueType.Equals

0 голосов
/ 29 ноября 2011

Не будучи настоящим экспертом в этой области, я бы просто пошел дальше и высказал свои мысли: в документации (по моему мнению) говорится, что если ваша структура имеет поле, которое является отражением объекта (ссылочного типа) не может следует избегать.

Так что если у вас есть следующее:

    public struct SomeStruct
    {
        public object ObjectTest
    }

ObjectTest нельзя сравнивать без отражения.Так что отражение будет использовано.Эта часть текста, кажется, говорит, что я прав:

" ValueType.Equals - Реализация по умолчанию метода Equals использует отражение для сравнения соответствующих полей obj иэкземпляр. "

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...