Подтвердить что ты не робот

Тип параметра для лет

Я пишу метод, который принимает год как параметр. То есть четырехзначное число, равное или меньшее, чем текущий год. Календарь только по-григориански (пока... не уверен в будущем), и мне, безусловно, ничего не понадобится 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);
}

Любые другие альтернативы, кроме написания моего собственного типа данных Year?

4b9b3361

Ответ 1

An int будет работать нормально в большинстве случаев.

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

Ответ 2

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

Ответ 3

Это сильно зависит от того, что вы планируете делать в этом году. Если вы планируете передавать его много, создание вашей специальной struct инкапсуляции int может быть хорошей идеей, потому что вам не нужно будет проверять одно и то же число несколько раз. В противном случае простой старый int будет работать нормально.

Ответ 4

Вы можете перенести его в неизменяемый struct, но в основном это int с некоторыми ограничениями.

Ответ 5

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

Ответ 6

Year is int. но если вы можете изменить его на свойство, вы можете добавить некоторую проверку в 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;
}

но если вы используете его только в одной функции, нет необходимости делать какие-либо из них, выполняйте свои проверки в ответственной функции.

Ответ 7

Я бы использовал int, если вы не планируете иметь дело с BC или не-григорианскими годами (с переходом между ними). В случае BC вам может понадобиться структура Year для отображения с помощью ToString. В случае, не относящемся к григорианскому делу, все усложняется.

Ответ 8

Хотя можно использовать 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);
    }
}

Ответ 9

Создайте пользовательский тип данных Year. Это быстрее, чем просить здесь о SO:-) Вы можете объявить его как struct для получения аналогичного поведения, например, при использовании int, но добавьте свое очень специфическое ограничение в логике типа.