2009-12-04 4 views
47

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

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 чувствует себя очень, очень грязно.

+0

Я определенно думаю, что класс DateRange может помочь. Я начал писать основы на некоторое время назад: http://www.adamjamesnaylor.com/2012/11/04/C-DateRange-Class.aspx –

+0

@AdamNaylor: ваши ссылки, кажется, не работают ... – testing

ответ

33

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

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

Приятно и легко пройти через, из-за генералитетов Marc shenanigans (при условии, что вы используете .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, но на данный момент у нас нет ничего похожего на диапазон ... Это хорошая идея, хотя - я добавил feature request.

+0

Извините, если я неправильно заговорил о Noda Time - кажется, это отлично подходит для людей, заинтересованных во времени. –

+0

Нет, это хорошо - если бы вы не упомянули об этом, я не уверен, думал ли я о добавлении запроса функции в проект :) Я думаю, что это довольно распространенное требование - сложный бит будет работать что нужно, чтобы приспособить различные настройки, которые люди захотят! –

+9

Интересный синтаксис. –

5

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

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

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

+0

О да , Нода. Ожидание этого .... –

+0

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

0

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

Я думаю, что вы хотите довольно здорово.

0

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

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

+0

Так что нетрудно иметь под-объект DateRange, но сохранить структуру плоской таблицы с столбцами начала и конца даты, используя NHibernate (Fluent)? Я бы так не подумал, но это хорошо знать заранее. –

+0

Вы можете реализовать свой DateRange как объект-значение и использовать его в NHibernate как «компонент». Затем вы можете сохранить структуру плоской таблицы с столбцами начала и окончания даты. –

5

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

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

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

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

Смежные вопросы