2009-12-04 10 views
47

Alcuni dei miei oggetti di dominio contengono gli intervalli di date come un paio di inizio e di fine proprietà:Devo creare un oggetto 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; } 
} 

e mi ritrovo con un sacco di questo:

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

L'ultimo mi ha fatto meraviglia ... Devo implementare una classe DateRange? Non sono a conoscenza di uno nel BCL.

Nella mia esperienza, rendere la gerarchia degli oggetti più profonda spesso complica le cose. Questi oggetti vengono inviati ai report RDLC visualizzati dal controllo ReportViewer, ma questo è secondario. Piegherò la vista sul modello piuttosto che viceversa. Noi non siamo legati ai nomi di proprietà, però, e sarebbe disposto a compromessi con qualcosa di simile: convalida

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

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

Un vantaggio di una classe DateRange sarebbe centralizzata della data di fine viene dopo la data di inizio, e che semplificherà il mio metodo di firme:

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

io non sono solo sicuro che una classe DateRange non mi entrare in più problemi che il suo valore. Opinioni?

Domanda laterale: ho perso una generica classe di tuple per uso generale nel BCL da qualche parte? So che ci sono alcuni molto specifici che fluttuano in vari spazi dei nomi. Inquinare le firme dei metodi di dominio pubblico con i tipi C5 sembra molto, molto sporco.

+0

Penso che una classe DateRange possa essere d'aiuto. Ho iniziato a scrivere le basi per un po 'di tempo fa: http://www.adamjamesnaylor.com/2012/11/04/C-DateRange-Class.aspx –

+0

@AdamNaylor: i tuoi link sembrano essere in calo ... – testing

risposta

33

No, non hai perso una lezione di carattere generale.

Ho un Range tipo in MiscUtil che potrebbe interessarti - e sicuramente rende semplice la manipolazione di DateTime. Riferendomi alla risposta di Marc, non riesco a ricordare se si tratti di una struttura o di una classe - naturalmente, sarebbe il caso di cambiarla.

È semplice e facile da eseguire, a causa dello stravagigazione generica di Marc (supponendo che si stia utilizzando .NET 3.5, almeno - è fattibile con 2.0 ma non supportato al momento);

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

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

(che è anche utilizzando un mazzo di metodi di estensione -. Più utile per il test di produzione)

Per affrontare l'altro punto, in risposta di Marc, Noda Time sarà certamente in grado di esprimere il concetto di una data più appropriatamente dell'API .NET, ma al momento non abbiamo nulla di simile a un intervallo ... È comunque una buona idea: ho aggiunto uno feature request.

+0

Scusate se ho parlato male di Noda Time - sembra un'ottima scelta per le persone interessate al tempo, però. –

+0

No, è bello - se non lo avessi menzionato, non sono sicuro se avrei pensato di aggiungere una richiesta di funzionalità al progetto :) Penso che sia un requisito abbastanza comune - la cosa complicata si risolverà cosa serve per sistemare le modifiche che la gente vorrà! –

+9

Sintassi interessante. –

5

Se si lavora molto con le date, sì, un intervallo può essere utile. Questo è in realtà uno di quei casi così raro in cui lo dovrebbe essere scrivendolo come struct (immutabile). Nota, comunque, che "Noda Time" probabilmente ti darà tutto questo e altro (quando è completo). Ho già fatto software di programmazione prima; Ho avuto un paio di tali strutture (per lavori leggermente diversi).

Nota, non esiste un pratico costrutto BCL per questo.

Inoltre, pensa a tutti i metodi meravigliosi (e possibilmente agli operatori) che puoi centralizzare quando hai una portata; "contiene" (di un datetime? di un altro intervallo? inclusi/esclusi i limiti?), "interseca", offset (un intervallo), ecc. Un definito caso per avere un tipo per gestirlo. Nota che a livello di ORM, questo è più facile se il tuo ORM supporta valori compositi - credo che NHibernate lo faccia, e possibilmente EF 4.0.

+0

Oh sì , Noda. Aspettandolo .... –

+0

Dato che questo è un refactoring per gestire meglio la manipolazione di date e range, suppongo che abbia senso dargli una lezione. Vorrei solo che stavo usando NHibernate su questo progetto. Tutte quelle ore hanno perso una bella scrittura se lo dico anch'io, ma in confronto, DAL. Il prossimo progetto, però. Ci sto giocando proprio ora per farcela. –

0

Non conosco alcuna classe nativa .NET della natura DateRange. La più vicina è probabilmente la combinazione DateTime + TimeSpan o DateTime/DateTime.

Penso che quello che vuoi sia abbastanza sano.

0

Come Mark e Jon hanno già menzionato, creerei questo come valore-tipo, che è immutabile. Io sceglierei di implementarlo come una struct e implementare le interfacce IEquatable e IComparable.

Quando si utilizza un ORM come NHibernate, sarà possibile memorizzare il tipo di valore all'interno di una tabella che rappresenta un'entità.

+0

Quindi non dovrebbe essere difficile avere un oggetto secondario DateRange ma mantenere la struttura piatta della tabella con le colonne Inizio e Fine data usando NHibernate (Fluent)? Non lo penserei, ma è bene sapere prima del tempo. –

+0

È possibile implementare DateRange come oggetto valore e utilizzarlo in NHibernate come "componente". Quindi, è possibile mantenere la struttura della tabella piatta con le colonne della data di inizio e fine. –

5

In .NET 4.0 o versione successiva è stato aggiunto il tipo Tuple < per gestire più valori.

Con il tipo di tupla è possibile definire la propria combinazione di valori al volo. Il tuo problema è molto comune ed è simile a quando una funzione vuole restituire più valori. In precedenza dovevi usare le variabili o creare una nuova classe solo per la risposta della funzione.

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

Qualunque strada si prende, penso che tu sia definitivamente prendendo l'approccio corretto. Stai dando un vero significato a ciò che sono due date insieme. Questo è un codice auto-documentante e nel modo migliore, proprio nella struttura del codice.