DateOfBirth值对象的平等性

时间:2018-02-02 12:27:53

标签: c#

请参阅以下代码:

public sealed class DateOfBirth : IEquatable<DateOfBirth>, IComparable<DateOfBirth>
    {
        private readonly DateTime _value;
        public DateOfBirth(DateTime dateOfBirth)
        {
            if(dateOfBirth == DateTime.MinValue)
                throw new ArgumentException("Invalid value.", "DateOfBirth");
            this._value= dateOfBirth.date;
        }

        public DateTime Value
        {
            get { return _value; }
        }

        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/ - 我对本文代码的唯一关注是比较方法没有这样做(我的代码所做的):

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

1 个答案:

答案 0 :(得分:0)

您不需要自己处理所有这些比较。相反,将比较工作委托给基础DateTime _value

MSDN包含有关how to override Equals method and overload == operator的全面文档。我认为此文档中没有任何内容可以添加。同样,由于您依赖于支持比较的基础值,您的:

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

可以简单地写成:

public static bool operator ==(DateOfBirth d1, DateOfBirth d2)
{
    return d1._value == d2._value;
}

同样,DateTime本身只是delegated the comparison to long

public struct DateTime : ...
{
    ...
    public static bool operator ==(DateTime d1, DateTime d2)
    {
        return d1.InternalTicks == d2.InternalTicks;
    }
}

请注意,由于DateTimestruct,因此您知道_value字段中的值始终为。{1}}。如果您使用class,情况会有所不同:在这种情况下,最简单的方法是在构造函数中禁止null值;在比较方法中处理它们也是可能的,但是需要更多代码并且更容易出错。

顺便说一句,确保你有充分的理由让DateOfBirth成为一个班级,而不是struct,并将其标记为密封。