Равенство значение DateOfBirth объекта


Пожалуйста, см. ниже код:

public sealed class DateOfBirth : IEquatable<DateOfBirth>, IComparable<DateOfBirth>
    {
        private readonly DateTime _value;

        public DateTime Value
        {
            get { return _value; }
        }
        public DateOfBirth(DateTime dateOfBirth)
        {
            if(dateOfBirth == DateTime.MinValue)
                throw new ArgumentException("Invalid value.", "DateOfBirth");
            this._value= dateOfBirth;
        }

        private static int Comparison(DateOfBirth dateOfBirth1, DateOfBirth dateOfBirth2)
        {
            if (ReferenceEquals(dateOfBirth1, dateOfBirth2))
                return 0;
            else if (ReferenceEquals(dateOfBirth1, null))
                return -1;
            else if (ReferenceEquals(dateOfBirth2, null))
                return 1;
            if (dateOfBirth1._value < dateOfBirth2._value)
                return -1;
            else if (dateOfBirth1._value == dateOfBirth2._value)
                return 0;
            else if (dateOfBirth1._value > dateOfBirth2._value)
                return 1;
            return 0;
        }

        public int CompareTo(DateOfBirth other)
        {
            if (other != null)
                return this._value.CompareTo(other._value);
            else
                throw new ArgumentNullException("DateOfBirth");
        }


        public static bool operator ==(DateOfBirth dateOfBirth1, DateOfBirth dateOfBirth2)
        {
            return Comparison(dateOfBirth1, dateOfBirth2) == 0;
        }

        public static bool operator !=(DateOfBirth dateOfBirth1, DateOfBirth dateOfBirth2)
        {
            return !(dateOfBirth1 == dateOfBirth2);
        }

        public static bool operator <(DateOfBirth dateOfBirth1, DateOfBirth dateOfBirth2)
        {
            return Comparison(dateOfBirth1, dateOfBirth2) < 0;
        }

        public static bool operator >(DateOfBirth dateOfBirth1, DateOfBirth dateOfBirth2)
        {
            return Comparison(dateOfBirth1, dateOfBirth2) > 0;
        }

        public static bool operator <=(DateOfBirth dateOfBirth1, DateOfBirth dateOfBirth2)
        {
            return Comparison(dateOfBirth1, dateOfBirth2) <= 0;
        }

        public static bool operator >=(DateOfBirth dateOfBirth1, DateOfBirth dateOfBirth2)
        {
            return Comparison(dateOfBirth1, dateOfBirth2) >= 0;
        }

        public bool Equals(DateOfBirth other)
        {
            if (ReferenceEquals(other, null))
                return false;
            return _value == other._value;
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as DateOfBirth);
        }

        public override int GetHashCode()
        {
            return _value.GetHashCode();
        }
    }

Я понимаю, что можно было бы утверждать, как за инженерными простое поле Дата рождения. Мне больше интересно, будет ли девять сравнения (https://ericlippert.com/2013/10/07/math-from-scratch-part-six-comparisons/) реализованы правильно. Эта статья помогла мне: https://blogs.msdn.microsoft.com/abhinaba/2005/10/11/c-comparison-operator-overloading-and-spaceship-operator/ - единственная забота у меня о коде в этой статье заключается в том, что Comparison способ не делать этого (что мой код делает):

if (ReferenceEquals(dateOfBirth1, dateOfBirth2))
                return 0;
            else if (ReferenceEquals(dateOfBirth1, null))

Вопрос 1) код выше подходит для цели (есть ли ошибки)?

В2) - это тип данных datetime (DateOfBirth.Пределах _value) подходит для даты рождения? возврат -1;

К3) - это проверка в конструкторе цели?



187
2
c#
задан 2 февраля 2018 в 10:02 Источник Поделиться
Комментарии
3 ответа


  • соответствовала своему назначению зависит от того, что именно это была за цель. Вы хотите регистрировать время рождения (как Value собственность предполагает), или только дата (как имя класса, кажется, подразумевает)? Должен ли он обрабатывать даты рождения до 0 Д. А.? Для этого нужно отклонить несуществующие даты (в зависимости от фактических исторических данных)?

  • Если этот класс предназначен для хранения только даты (не времени составляющей), тогда это имеет больше смысла, чтобы дать ему Year, Month и Day свойства, а не Value свойство, которое предоставляет компонент времени.

  • DateTime.MinValue это значение по умолчанию DateTime, но почему то делает это недопустимая дата рождения?

  • Это могут быть полезны в качестве (явного или неявного) преобразования операторов от и до DateTimeи, возможно, методами анализа, в зависимости от того, где и как этот класс предназначен для использования. Однако...

  • ...цель этого класса кажется очень узкой. Судя по другим вашим постам, вы задумались о создании многих типов такое "значение"? Это много работы (по крайней мере в C#), но какую проблему это решит? А где добавленная стоимость? Вы беспокоитесь, что кто-то может случайно назначить экспирации-дата рождения-дата поле? Помните, все, что дополнительный код должен быть сохранен, и есть расходы, связанные с этим.

Мое впечатление, что да, ты-технических. Я подозреваю, что вы найдете больше значение в написании автоматизированных тестов (что, когда все сделано правильно, должна была заметить >= оператор баг, и должен поймать истечения срока-дата/дата рождения вероятность перепутывания точно также), чем при добавлении такого рода сложности. C# требует слишком много котел-плита для того чтобы этот подход жизнеспособен, если на кону жизни я бы не стал заморачиваться.


Редактировать: несколько примечаний:


  • В C# 7, ReferenceEquals(a, null) может быть написано более кратко как a is null.

  • Нулевой чек в CompareTo использует перегруженный != оператора, но вы могли бы также использовать ссылку проверить непосредственно.

  • Почему Equals методы не использую Comparison? То же самое касается != оператор: почему не сделать Comparison(dateOfBirth1, dateOfBirth2) != 0?

3
ответ дан 2 февраля 2018 в 03:02 Источник Поделиться

конструктор

Это выглядит странно, что прошло DateTime параметр называется dateOfBirth. Читатель кода может запутаться, потому что в основном вы используете DateOfBirth dateOfBirthX попра X стенды для 1 или 2.

Метод compareto()

Код не соответствует документации IComparable<T>.CompareTo котором говорится в слове


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

смысл, если other == null этот метод должен возвращать значение > 0. Исключение будет довольно запутанным, если e.г у вас есть List<DateOfBirth>, где допустимо добавлять nullи попробуйте Sort() чтобы получить ArgumentNullException.

Сравнение()

Этот метод должен быть упрощен, потому что вы не должны проверить, если dateOfBirth1._value == dateOfBirth2._value если вы в конце способ вернуть 0 в любом случае.

Пока мы находимся на этой if..else if..else if.... вы должны сделать себе одолжение и использовать брекеты {} хотя они могут быть необязательными. Опущение подтяжки может привести к скрытым и поэтому трудно найти ошибки.

private static int Comparison(DateOfBirth dateOfBirth1, DateOfBirth dateOfBirth2)
{
if (ReferenceEquals(dateOfBirth1, dateOfBirth2))
{
return 0;
{
else if (ReferenceEquals(dateOfBirth1, null))
{
return -1;
}
else if (ReferenceEquals(dateOfBirth2, null))
{
return 1;
}
if (dateOfBirth1._value < dateOfBirth2._value)
{
return -1;
}
else if (dateOfBirth1._value > dateOfBirth2._value)
{
return 1;
}
return 0;
}

2
ответ дан 2 февраля 2018 в 05:02 Источник Поделиться

Я согласен, что другие два ответа. Этот класс не добавляет ничего, что могло бы сделать его более полезным, чем обычный DateTime.


Другие вопросы, которые не решены еще...


public DateTime Value
{
get { return _value; }
}

Представляя это свойство делает работу с DateOfBrith просто более запутанной. Это дает пользователю прямой доступ к данным нижележащих. Это подрывает весь смысл инкапсуляции и сокрытия дату рождения как чисто DateTime.


Но не только это. Он также использует довольно бесполезным исключения:


public DateOfBirth(DateTime dateOfBirth)
{
if(dateOfBirth == DateTime.MinValue)
throw new ArgumentException("Invalid value.", "DateOfBirth");
this._value= dateOfBirth;
}

В ArgumentException уже означает, что некоторое значение является недействительным, поэтому пишу это сообщение не поможет. Я ожидаю, что вы скажите мне, почему он был недействительным и что я должен использовать, чтобы сделать его действительным. Другой аргумент также вводит в заблуждение. Аргумент имя dateOfBirth и не DateOfBirth. Вы должны использовать nameof() здесь в любом случае. Никто не использует такие harcoded строк.



public int CompareTo(DateOfBirth other)
{
if (other != null)
return this._value.CompareTo(other._value);
else
throw new ArgumentNullException("DateOfBirth");
}

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

Но как @Heslacher сказал, это не должно быть даже бросать какие-либо исключения.



(DateOfBirth dateOfBirth1, DateOfBirth dateOfBirth2)

Я нахожу имена аргументов немного странно. По Конвенции они обычно называются left и right для откуда они берутся или x и y и не какое имя+номер.


Реализация также inconsitent. Вы перенаправить всех операторов Comparison но изобретать колесо здесь


public bool Equals(DateOfBirth other)
{
if (ReferenceEquals(other, null))
return false;
return _value == other._value;
}

поступая точно так же проверить равенство, как вы уже делали ранее.

2
ответ дан 2 февраля 2018 в 11:02 Источник Поделиться