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