2009-12-04 17 views
47

Algunos de mis objetos de dominio contienen rangos de fechas como un par de propiedades de inicio y de finalización:¿Debo hacer un objeto 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; } 
} 

y me encuentro con un montón de esto:

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); 

El último que me hizo Me pregunto ... ¿Debo implementar una clase DateRange? No conozco ninguno en el BCL.

En mi experiencia, hacer que la jerarquía de objetos sea más profunda a menudo complica las cosas. Estos objetos se envían a informes RDLC mostrados por el control ReportViewer, pero eso es secundario. Doblaré la vista hacia el modelo y no al revés. No estamos atados a los nombres de las propiedades, sin embargo, y estaría dispuesto a comprometer con algo como: validación

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

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

Un beneficio de una clase DateRange estaría centralizada de la fecha de finalización viene después de la fecha de inicio y simplificará mi método firmas:

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

yo no estoy seguro de que una clase DateRange no me va a entrar en más problemas de lo que vale. Opiniones?

Pregunta adicional: ¿Extraño una clase genérica de tuplas de propósito general en el BCL en alguna parte? Sé que hay algunos muy específicos flotando en varios espacios de nombres. La contaminación de mis firmas de métodos de dominio público con tipos C5 parece muy, muy sucia.

+0

Definitivamente creo que una clase DateRange puede ayudar. Empecé a escribir las bases por un tiempo: http://www.adamjamesnaylor.com/2012/11/04/C-DateRange-Class.aspx –

+0

@AdamNaylor: Tus enlaces parecen estar caídos ... – testing

Respuesta

33

No, no se perdió una clase de propósito general.

Tengo Range tipo en MiscUtil que usted puede estar interesado - y ciertamente hace la manipulación simple DateTime. Refiriéndome a la respuesta de Marc, no puedo recordar si se trata de una estructura o una clase; por supuesto, puedes cambiarlo.

Es agradable y fácil de pasar, debido a las travesuras genéricas de Marc (suponiendo que estés usando .NET 3.5, al menos - es factible con 2.0 pero no es compatible en este momento);

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

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

(Eso también el uso de un montón de métodos de extensión -. Más útil para la prueba de producción)

Para abordar el otro punto en la respuesta de Marc, Noda Time sin duda será capaz de expresar el concepto de una fecha más apropiadamente que la API .NET, pero no tenemos nada como un rango en este momento ... Aunque es una buena idea, he agregado un feature request.

+0

Disculpe si hablé mal de Noda Time, pero parece una excelente opción para las personas interesadas en el tiempo. –

+0

No, es bueno, si no lo mencionó, no estoy seguro de si habría pensado agregar una solicitud de función al proyecto :) Creo que es un requisito bastante común: el truco se resolverá ¡Lo que se necesita para acomodar los diversos ajustes que la gente querrá! –

+9

Interesante sintaxis. –

5

Si trabajas mucho con las fechas, sí, un rango puede ser útil. Este es en realidad uno de esos casos tan raros en los que debería escribirlo probablemente como struct (inmutable). Tenga en cuenta, sin embargo, que "Noda Time" probablemente le proporcione todo esto y más (cuando esté completo). He hecho el software de programación antes; Tenía un par de tales estructuras (para trabajos ligeramente diferentes).

Nota, no hay una construcción BCL útil para esto.

Además, piense en todos los maravillosos métodos (y posiblemente operadores) que puede centralizar cuando tiene un rango; "contiene" (de una fecha y hora? de otro rango? incluidos/excluidos los límites?), "intersecta", desplazado por (un intervalo de tiempo), etc. Un definido caso por tener un tipo para manejarlo. Tenga en cuenta que en el nivel ORM, esto es más fácil si su ORM admite valores compuestos, creo que NHibernate sí, y posiblemente EF 4.0.

+0

Oh sí Noda Esperando ... –

+0

Dado que se trata de una refactorización para manejar mejor la manipulación de fechas y rangos, supongo que tiene sentido darle una clase. Ojalá estuviera usando NHibernate en este proyecto. Todas esas horas perdidas escribiendo bastante bien si me lo digo a mí mismo, pero pálido en comparación, DAL. El próximo proyecto, sin embargo. Estoy jugando con eso ahora mismo para entenderlo. –

0

No conozco ninguna clase .NET nativa de la naturaleza DateRange. El más cercano es probablemente la combinación de DateTime + TimeSpan o DateTime/DateTime.

Creo que lo que quieres es bastante bueno.

0

Como Mark y Jon ya mencioné, crearía esto como un valor-tipo, que es inmutable. Optaría por implementarlo como una estructura, e implementar las interfaces IEquatable e IComparable.

Al usar un ORM como NHibernate, podrá almacenar el tipo de valor dentro de una tabla que representa una entidad.

+0

Entonces, no debería ser difícil tener un subobjeto DateRange, pero mantener la estructura de la tabla plana con las columnas de fecha de inicio y finalización usando NHibernate (Fluent)? No lo creo, pero es bueno saberlo con anticipación. –

+0

Puede implementar su DateRange como un objeto de valor y usarlo en NHibernate como un 'componente'. Entonces, de hecho puede mantener la estructura de la tabla plana con columnas de fecha de inicio y finalización. –

5

En .NET 4.0 o superior, se ha agregado el tipo Tuple <> para manejar varios valores.

Con el tipo de tupla, puede definir su propia combinación de valores sobre la marcha. Su problema es muy común y es similar a cuando una función quiere devolver múltiples valores. Anteriormente, tenía que usar variables o crear una nueva clase solo para la respuesta de la función.

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

Cualquiera que sea la ruta que tome, creo que definitivamente está tomando el enfoque correcto. Estás dando un significado real a las dos fechas juntas. Es código de auto-documentación y de la mejor manera, directamente en la estructura del código.

Cuestiones relacionadas