年份的参数类型

本文关键字:类型 参数 | 更新日期: 2023-09-27 18:16:25

我正在编写一个接受year作为参数的方法。即等于或小于当前年份的四位数。日历只有格里高利历(目前…我不确定未来),我肯定不需要任何BC。

我要使用哪种数据类型?显而易见的解决方案是使用DateTime或Int32:

public void MyFunction(DateTime date)
{
     // year to work with: date.Year;
     // date.Month, date.Day, etc. is irrelevant and will always be
}

public void MyFunction(Int year)
{
     if ( year > 9999 || otherValidations == false )
     {
         //throw new Exception...
     }
     // year to work with: new DateTime(year, 1, 1);
}

除了编写我自己的自定义数据类型之外,还有其他选择吗?

年份的参数类型

在大多数情况下,int都可以正常工作。

这就是DateTime.Year是什么,这就是DateTime构造函数所接受的,所以除非你有特殊的原因需要另一种数据类型,整数可能是最容易处理的。

可能是int。接受整个DateTime对象会令人困惑,因为您的方法只需要年份。从这里开始,int是合乎逻辑的选择,因为它是DateTime的类型。年产权。

这在很大程度上取决于你这一年计划做什么。如果您打算多次传递它,创建您的自定义struct封装一个int可能是一个好主意,因为您不需要多次验证相同的数字。否则,一个普通的旧int就可以了。

你可以把它包装成不可变的struct,但基本上它int加上一些限制。

我会说:选择DateTime,因为您已经定义了可能需要的操作。为什么要重新发明轮子?

年份为整型。但是如果你可以把它改成属性,你可以在set中添加一些验证,如果只是输入一些函数,你可以添加新的函数来验证它。

int year;
public int Year
{
    get
    {
        if (year > 9999)
          throw ...
        // check other constrains ...
        return year;
    }
    set
    {
       if (value > 9999)
         throw ...
       // check other constrains ...
       year = value;
    }
}

作为函数:

int GetYear(int year)
{
   do validation and possibly throw an exception
   return year;
}

但是如果你只在一个函数中使用它,就不需要做任何一个,在负责的函数中做你的验证

我会使用int,除非您计划必须处理BC年或非公历年(以及它们之间的转换)。在BC的情况下,您可能需要一个Year结构体,以便通过ToString显示。在非格里高利历的情况下,事情变得更加复杂。

虽然可以使用int,但最好的方法是实现一个专门的结构体,因为它能更好地表达您的意图:

public struct Year : IEquatable<Year>, IEquatable<DateTime>, IEquatable<int>
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="year"></param>
    /// <exception cref="ArgumentOutOfRangeException">
    ///     When <see cref="year"/> is not within the range from <value>1</value> to <value>9999</value>.
    /// </exception>
    public Year(int year)
    {
        // same limits as DateTime 
        // be careful when changing this values, because it might break
        // conversion from and to DateTime 
        var min = 1;
        var max = 9999;
        if (year < min || year > max)
        {
            var message = string.Format("Year must be between {0} and {1}.", min, max);
            throw new ArgumentOutOfRangeException("year", year, message);
        }
        _value = year;
    }
    private readonly int _value;
    public bool Equals(Year other)
    {
        return _value == other._value;
    }
    public bool Equals(DateTime other)
    {
        return _value == other.Year;
    }
    public bool Equals(int other)
    {
        return _value == other;
    }
    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }
        if (obj is Year) return Equals((Year) obj);
        if (obj is int) return Equals((int)obj);
        if (obj is DateTime) return Equals((DateTime) obj);
        return false;
    }
    public static Year MinValue 
    {
        get
        {
            return new Year(DateTime.MinValue.Year);
        }
    }
    public static Year MaxValue
    {
        get
        {
            return new Year(DateTime.MaxValue.Year);
        }
    }
    public override int GetHashCode()
    {
        return _value;
    }
    public static bool operator ==(Year left, Year right)
    {
        return left.Equals(right);
    }
    public static bool operator !=(Year left, Year right)
    {
        return !left.Equals(right);
    }
    public override string ToString()
    {
        return _value.ToString();
    }
    public string ToString(IFormatProvider formatProvider)
    {
        return _value.ToString(formatProvider);
    }
    public string ToString(string format)
    {
        return _value.ToString(format);
    }
    public string ToString(string format, IFormatProvider formatProvider)
    {
        return _value.ToString(format, formatProvider);
    }
    public DateTime ToDateTime()
    {
        return new DateTime(_value, 1, 1);
    }
    public int ToInt()
    {
        return _value;
    }
    public static implicit operator DateTime(Year year)
    {
        return new DateTime(year._value, 1, 1);
    }
    public static explicit operator Year(DateTime dateTime)
    {
        return new Year(dateTime.Year);
    }
    public static explicit operator int(Year year)
    {
        return year._value;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="year"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentOutOfRangeException">
    ///     When <see cref="year"/> is not within the range from <value>1</value> to <value>9999</value>.
    /// </exception>
    public static explicit operator Year(int year)
    {
        return new Year(year);
    }
}

写一个自定义数据类型Year。它比在SO上询问更快:-)您可以将其声明为struct以接收与使用int类似的行为,但在类型的逻辑中添加您非常特定的约束。