Как работают методы EqualOperator () и NotEqualOperator () в этой реализации ValueObject (Microsoft Docs)?

В области проектирования, ориентированного на предметную область, мы знакомимся с концепцией ValueObject, в которой объекты не имеют идентичности.

У Microsoft есть предоставили реализацию своего ValueObject в своей серии микросервисов, где они переопределяют Equals(), так что два ValueObject с одинаковыми значениями считаются идентичными.

Я включил их реализацию ниже, но мой вопрос касается методов EqualOperator() и NotEqualOperator() - как это работает? когда они называются?

Я знаком с перегрузка оператора, но похоже, что это реализация, которую я раньше не видел, и я не могу найти никакой документации по ней.

Вот реализация:

public abstract class ValueObject
{
    protected static bool EqualOperator(ValueObject left, ValueObject right)
    {
        if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null))
        {
            return false;
        }

        return ReferenceEquals(left, null) || left.Equals(right);
    }

    protected static bool NotEqualOperator(ValueObject left, 
        ValueObject right)
    {
        return !(EqualOperator(left, right));
    }

    protected abstract IEnumerable<object> GetAtomicValues();

    public override bool Equals(object obj)
    {
        if (obj == null || obj.GetType() != GetType())
        {
            return false;
        }

        ValueObject other = (ValueObject)obj;
        IEnumerator<object> thisValues = GetAtomicValues().GetEnumerator();
        IEnumerator<object> otherValues = 
            other.GetAtomicValues().GetEnumerator();

        while (thisValues.MoveNext() && otherValues.MoveNext())
        {
            if (ReferenceEquals(thisValues.Current, null) ^
                ReferenceEquals(otherValues.Current, null))
            {
                return false;
            }

            if (thisValues.Current != null &&
                !thisValues.Current.Equals(otherValues.Current))
            {
                return false;
            }
        }

        return !thisValues.MoveNext() && !otherValues.MoveNext();
    }

    // Other utilility methods
}

Вот пример их использования:

public class Address : ValueObject
{
    public String Street { get; private set; }
    public String City { get; private set; }
    public String State { get; private set; }
    public String Country { get; private set; }
    public String ZipCode { get; private set; }

    private Address() { }

    public Address(string street, string city, string state, string country,
        string zipcode)
    {
        Street = street;
        City = city;
        State = state;
        Country = country;
        ZipCode = zipcode;
    }

    protected override IEnumerable<object> GetAtomicValues()
    {
         // Using a yield return statement to return 
         // each element one at a time

         yield return Street;
         yield return City;
         yield return State;
         yield return Country;
         yield return ZipCode;
     }
 }
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
837
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

На самом деле, я нахожу удивительным, что Microsoft реализовала тип значения с помощью класса. Обычно для этой цели лучше подходят структуры, если только ваши объекты-значения не становятся очень большими. Для большинства случаев использования таких типов значений, как координаты или цвета, это не так.

Оставляя это обсуждение в стороне, здесь происходит следующее: если вы реализуете объект значения, вам необходимо правильно реализовать Equals и GetHashCode, которые последовательно включают друг друга. Однако эти два метода на самом деле не очень сложны, но многословны для реализации: вам нужно преобразовать объект, а затем проверить каждое из его свойств. Если вы используете классы, у вас есть дополнительный шаблонный фактор, который заключается в том, что вы обычно хотите ускорить проверку равенства с помощью проверки равенства ссылок. То есть два объекта не обязательно должны быть одно и тоже, чтобы быть равный, но если они являются одно и тоже, то они также равны.

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

Теперь, что касается фактического вопроса о том, когда на самом деле вызываются EqualOperator и NotEqualOperator, я бы предположил, что это просто вспомогательные функции, упрощающие реализацию операторов: вы должны предоставить перегруженный оператор ==, который просто возвращает EqualOperator и !=, который просто возвращает NotEqualOperator. Вы можете спросить, почему базовый класс типа значения не имеет этих операторов? Что ж, я думаю, это потому, что это будет означать, что компилятор позволит вам применять == и != к различным типам объектов значений с помощью перегруженного оператора.

У структур есть недостатки - нет возможности скрыть конструктор по умолчанию, нет наследования, плохая поддержка в Entity Framework <Core 2.0 и т. д.

guillaume31 09.03.2018 16:59

Я был бы согласен с вами относительно структур, но я думаю, что @ guillaume31 попал в точку с этим примером в его поддержке EF. Спасибо за ответ, это именно то, что мне нужно было знать.

Matt Griffiths 09.03.2018 19:40

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