Должен ли я сделать объект DateRange? - PullRequest
57 голосов
/ 04 декабря 2009

Некоторые из моих доменных объектов содержат диапазоны дат в виде пары свойств даты начала и окончания:

public class Period {
  public DateTime EffectiveDate { get; set; }
  public DateTime ThroughDate { get; set; }
}

public class Timeline {
  public DateTime StartDate { get; set; }
  public DateTime EndDate { get; set; }
}

И я обнаружил, что многое из этого:

abstract public int Foo(DateTime startDate, DateTime endDate);
abstract public decimal Bar(DateTime startDate, DateTime endDate);
abstract public ICollection<C5.Rec<DateTime, DateTime>> FooBar(DateTime startDate, DateTime endDate);

Последнее заставило меня задуматься ... Должен ли я реализовать класс DateRange? Я не знаю ни одного в BCL.

По моему опыту, углубление иерархии объектов часто усложняет ситуацию. Эти объекты отправляются в отчеты RDLC, отображаемые элементом управления ReportViewer, но это вторично. Я согну вид модели, а не наоборот. Однако мы не привязаны к именам свойств и готовы пойти на компромисс с чем-то вроде:

public class DateRange {
  public DateTime StartDate { get; set; }
  public DateTime EndDate { get; set; }
}

Period p = new Period();
DateTime t = p.EffectiveDateRange.StartDate;

Преимуществом класса DateRange будет централизованная проверка даты окончания, наступающей после даты начала, и это упростит сигнатуры моего метода:

abstract public int Foo(DateRange dateRange);
abstract public decimal Bar(DateRange dateRange);
abstract public ICollection<DateRange> FooBar(DateRange dateRange);

Я просто не уверен, что класс DateRange не доставит мне больше неприятностей, чем стоит. Мнения?

Дополнительный вопрос: я где-то пропустил универсальный класс кортежей общего назначения в BCL? Я знаю, что есть несколько очень специфических, плавающих в разных пространствах имен. Загрязнение моих сигнатур методов общественного достояния типами C5 выглядит очень, очень грязно.

Ответы [ 5 ]

38 голосов
/ 04 декабря 2009

Нет, вы не пропустили урок общего назначения.

У меня есть Range тип в MiscUtil , который может вас заинтересовать - и это, безусловно, делает для простой DateTime манипуляции. Ссылаясь на ответ Марка, я не могу вспомнить, является ли это структурой или классом - вы можете изменить его, конечно.

Это приятно и легко пройти, благодаря стандартным махинациям Марка (при условии, что вы используете .NET 3.5, по крайней мере - это возможно с 2.0, но в данный момент не поддерживается);

Range<DateTime> range = 19.June(1976).To(DateTime.Today);

foreach (DateTime date in range.Step(1.Days())
{
    // I was alive in this day
}

(Это также использует кучу методов расширения - более полезных для тестирования, чем для производства.)

Чтобы ответить на другой вопрос в ответе Марка, Noda Time , безусловно, сможет выразить концепцию даты более подходящим образом, чем .NET API, но у нас нет ничего подобного момент ... Это хорошая идея - я добавил запрос функции .

9 голосов
/ 29 мая 2015

В .NET 4.0 или выше был добавлен тип Tuple <> для обработки нескольких значений.

С помощью типа кортежа вы можете определить собственную комбинацию значений на лету. Ваша проблема очень распространена и похожа на то, когда функция хочет вернуть несколько значений. Ранее вам приходилось использовать переменные или создавать новый класс только для ответа функции.

Tuple<DateTime, DateTime> dateRange =
    new Tuple<DateTime, DateTime>(DateTime.Today, DateTime.Now);

Какой бы путь вы ни выбрали, я думаю, вы определенно выбираете правильный подход. Вы даете реальное значение тому, что две пары в паре вместе. Это самодокументированный код, и в лучшем случае, прямо в структуре кода.

5 голосов
/ 04 декабря 2009

Если вы много работаете с датами, да - диапазон может быть полезен. На самом деле это один из тех редких случаев, когда вы должны , вероятно, напишите его как struct (неизменный). Обратите внимание, однако, что «Время Нода», вероятно, даст вам все это и даже больше (когда оно будет завершено). Я сделал планирование программного обеспечения раньше; У меня было несколько таких структур (для немного другой работы).

Обратите внимание, для этого нет удобной конструкции BCL.

Также - подумайте обо всех замечательных методах (и, возможно, операторах), которые вы можете централизовать, когда у вас есть диапазон; «содержит» (дата / время другого диапазона, включая / исключая пределы?), «пересекает», смещение (интервал времени) и т. д. определенный случай для наличия типа для обработки. Обратите внимание, что на уровне ORM это проще, если ваш ORM поддерживает составные значения - я полагаю, что NHibernate поддерживает, и, возможно, EF 4.0.

0 голосов
/ 04 декабря 2009

Как уже упоминали Марк и Джон, я бы создал это как тип значения, который является неизменным. Я бы предпочел реализовать его как структуру и реализовать интерфейсы IEquatable и IComparable.

При использовании ORM, такого как NHibernate, вы сможете хранить тип значения в таблице, которая представляет сущность.

0 голосов
/ 04 декабря 2009

Я не знаю ни одного нативного класса .NET природы DateRange. Наиболее близким, вероятно, является комбинация DateTime + TimeSpan или DateTime / DateTime.

Я думаю, что вы хотите, чтобы это было достаточно.

...