Есть ли лучший способ внедрить Equals для объекта с большим количеством полей?

StackOverflow https://stackoverflow.com/questions/1831747

Вопрос

смотрите также Как быстро проверить, имеют ли данные переданные двум объектам одинаковые свойства в C #?

У меня есть много объектов передачи данных (DTO), каждый из которых содержит множество простых полей.Мне нужно реализовать Equals для всех из них (чтобы я мог написать несколько модульных тестов, передающих их в WCF).

Код, который я использую, является:

public override bool Equals(object rhs)
{

    RequestArguments other = rhs as RequestArguments;

    return
       other != null && 
       other.m_RequestId.Equals(RequestId) && 
       other.m_Type.Equals(m_Type) && 
       other.m_Parameters.Equals(m_Parameters) && 
       other.m_user.Equals(m_user);
}

Должен быть способ получше!... (перечисление всех полей скорее указывает на наличие ошибок и проблем с обслуживанием)

Например.у нас есть Объект.MemberwiseClone(), чтобы помочь с Cloning(), но я не могу найти ничего, что могло бы помочь с Equals.Мы работаем в условиях полного доверия, поэтому решение, основанное на рефлексии, - это один из ответов, но я предпочел бы не изобретать велосипед.

(Извините, мы не генерируем DTO на языке, зависящем от домена, иначе подобные вещи были бы простыми!Также я не могу изменить систему сборки, чтобы добавить еще один шаг)

Это было полезно?

Решение

Забавно, что вы спросили, но недавно я опубликовал некоторый код для выполнения именно этого.Посмотри на мой Memberwise Equalityкомпаратор чтобы посмотреть, соответствует ли это вашим потребностям.

Он действительно прост в использовании и к тому же довольно эффективен.Он использует IL-emit для генерации всей функции Equals и GetHashCode при первом запуске (по одному разу для каждого используемого типа).Он будет сравнивать каждое поле (частное или общедоступное) данного объекта, используя средство сравнения равенства по умолчанию для этого типа (EqualityComparer.По умолчанию).Мы уже некоторое время используем его в производстве, и он кажется стабильным, но я не оставлю никаких гарантий =)

Он устраняет все те досадные крайние случаи, о которых вы редко думаете, когда запускаете свой собственный метод equals (т. Е. вы не можете сравнить свой собственный объект с null, если вы сначала не поместили его в объект, и многие другие проблемы, связанные с null, исключены).

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

public override int GetHashCode()
{
    return MemberwiseEqualityComparer<Foo>.Default.GetHashCode(this);
}

public override bool Equals(object obj)
{
    if (obj == null)
        return false;

    return Equals(obj as Foo);
}

public override bool Equals(Foo other)
{
    return MemberwiseEqualityComparer<Foo>.Default.Equals(this, other);
}

MemberwiseEqualityComparer выпущен в соответствии с MIT license я думаю, что вы можете делать с ним практически все, что захотите, включая использование в проприетарных решениях без каких-либо изменений в лицензировании.

Другие советы

Одним из вариантов является использование отражения для получения всех доступных полей, а затем получения и сравнения их значений для нужных объектов.Это дало бы вам общее решение, но вам пришлось бы немало поработать, вероятно, использование хэшей, как предлагает Алекс, является более чистым решением.

Редактировать:Вот простой пример сравнения объектов с использованием отражения, он рассматривает свойства, а не поля, но вы поняли идею: http://www.willasrari.com/blog/use-systemreflection-for-comparing-custom-objects/000257.aspx

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

Редактировать:извините, я не заметил, что вы запрашиваете тестирование сериализации.Так что этот подход определенно не работает для вас.


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

Это довольно медленно, но должно быть достаточно надежным и простым в реализации.

Иногда мы делаем это, чтобы проверить, не изменил ли кто-нибудь какие-либо данные в редакторе.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top