2009-12-04 6 views
47

Ein paar meiner Domain-Objekte enthalten Datumsbereiche als ein Paar von Start- und Enddatum Eigenschaften:Soll ich ein DateRange-Objekt erstellen?

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

Und ich finde mich mit viel dies:

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

Die letzte mir gemacht frage mich ... Sollte ich eine DateRange-Klasse implementieren? Ich kenne keinen in der BCL.

Nach meiner Erfahrung kompliziert die Objekthierarchie oft die Dinge. Diese Objekte werden an RDLC-Berichte gesendet, die vom ReportViewer-Steuerelement angezeigt werden, aber das ist zweitrangig. Ich werde den Blick auf das Modell richten und nicht umgekehrt. Wir sind nicht auf die Eigenschaftsnamen gebunden, aber, und mit etwas zu Kompromissen bereit wären, wie:

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

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

Ein Vorteil einer Klasse Daterange zentralisiert Validierung des Enddatum nach dem Startdatum kommen würde, und

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

ich bin nur nicht sicher, dass eine Daterange-Klasse bekommt mich nicht in mehr Mühe als sein wert: es wird meine Methode Signaturen vereinfachen. Meinungen?

Side question: Habe ich irgendwo im BCL eine generische Tuple-Klasse für allgemeine Zwecke übersehen? Ich weiß, dass einige sehr spezifische in verschiedenen Namensräumen herumlaufen. Die Verschmutzung meiner Public-Domain-Methodensignaturen mit C5-Typen fühlt sich sehr, sehr dreckig an.

+0

Ich denke auf jeden Fall, dass eine DateRange-Klasse helfen kann. Ich begann eine den Grundstein zu schreiben eine Weile zurück: http://www.adamjamesnaylor.com/2012/11/04/C-DateRange-Class.aspx –

+0

@AdamNaylor: Ihre Links unten zu sein scheint ... – testing

Antwort

33

Nein, Sie haben keine allgemeine Klasse vermisst.

Ich habe einen Range Typ in MiscUtil, die Sie interessiert sein könnten - und es macht sicherlich für einfache DateTime Manipulation. Mit Bezug auf Marc's Antwort kann ich mich nicht erinnern, ob dies eine Struktur oder eine Klasse ist - Sie können es natürlich gerne ändern.

Es ist schön und leicht, durch Marc generics shenanigans (vorausgesetzt, Sie verwenden mindestens .NET 3.5 - es ist machbar mit 2.0, aber nicht unterstützt im Moment);

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

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

(Das ist auch eine Reihe von Erweiterungsmethoden verwenden -. Nützliche für Test als Produktion)

den anderen Punkt in Marcs Antwort zu adressieren, Noda Time wird sicherlich in der Lage sein, das Konzept eines Datum auszudrücken passender als die .NET-API, aber im Moment haben wir noch nichts wie eine Reihe ... Es ist eine gute Idee - ich habe eine feature request hinzugefügt.

+0

Tut mir leid, wenn ich über Noda Time falsch gesprochen habe - es scheint eine ausgezeichnete Lösung für Leute zu sein, die sich für die Zeit interessieren. –

+0

Nein, es ist gut - wenn du es nicht erwähnt hättest, bin ich mir nicht sicher, ob ich daran gedacht hätte, dem Projekt eine Feature-Anfrage hinzuzufügen :) Ich denke, es ist eine ziemlich häufige Anforderung - das knifflige Bit wird funktionieren was benötigt wird, um die verschiedenen Optimierungen unterzubringen, die Leute wollen! –

+9

Interessante Syntax. –

5

Wenn Sie viel mit Daten arbeiten, ja - ein Bereich kann praktisch sein. Dies ist tatsächlich einer dieser ach so seltenen Fälle, in denen Sie sollten wahrscheinlich schreiben Sie es als struct (unveränderlich). Beachten Sie jedoch, dass "Noda Time" Ihnen wahrscheinlich all dies und mehr geben wird (wenn es vollständig ist). Ich habe vorher Software geplant. Ich hatte ein paar solcher Strukturen (für etwas andere Jobs).

Hinweis, es gibt kein praktisches BCL-Konstrukt dafür.

Auch - denken Sie an all die wunderbaren Methoden (und möglicherweise Operatoren), die Sie zentralisieren können, wenn Sie eine Reichweite haben; "contains" (eines datetime? eines anderen Bereichs? including/exclusive limits?), "intersects", offset-by (eine Zeitspanne) usw. A definitve Fall für einen Typ, um damit umzugehen. Beachten Sie, dass dies auf der ORM-Ebene einfacher ist, wenn Ihr ORM zusammengesetzte Werte unterstützt - ich glaube, NHibernate und möglicherweise EF 4.0.

+0

Oh ja , Noda. Wartet darauf .... –

+0

Da dies ein Refactoring ist, um Datums- und Bereichsmanipulationen besser zu handhaben, nehme ich an, dass es Sinn macht, ihm eine Klasse zu geben. Ich wünschte nur, ich würde NHibernate für dieses Projekt verwenden. All diese Stunden haben mir ziemlich gut gefallen, wenn ich das selbst sage, aber im Vergleich dazu blass, DAL. Nächstes Projekt. Ich spiele gerade damit, um den Dreh raus zu kriegen. –

0

Ich kenne keine native .NET-Klasse der DateRange-Natur. Der nächste ist wahrscheinlich DateTime + TimeSpan oder DateTime/DateTime Kombination.

Ich denke, was Sie wollen, ist ziemlich solide.

0

Als Mark und Jon bereits erwähnt, würde ich dies als Wert-Typen erstellen, die unveränderlich ist. Ich würde entscheiden, es als eine Struktur zu implementieren, und die Schnittstellen IEquatable und IComparable zu implementieren.

Wenn ein ORM wie NHibernate verwenden, werden Sie den Werttyp in einer Tabelle speichern können, die eine Einheit darstellt.

+0

Also sollte es nicht schwierig sein, ein DateRange-Unterobjekt zu haben, aber die flache Tabellenstruktur mit den Spalten Start und Enddatum über NHibernate (Fluent) zu behalten? Ich würde nicht denken, aber es ist gut, im Voraus zu wissen. –

+0

Sie können Ihren DateRange als Wertobjekt implementieren und in NHibernate als "Komponente" verwenden. Dann können Sie tatsächlich die flache Tabellenstruktur mit Spalten für Start- und Enddatum beibehalten. –

5

In .NET 4.0 oder höher die Tuple <> Typ mehrere Werte zu handhaben wurde hinzugefügt.

Mit dem Tupel-Typ Sie Ihre eigene Kombination von Werten on the fly definieren können. Ihr Problem ist sehr häufig und ähnelt dem, wenn eine Funktion mehrere Werte zurückgeben möchte. Zuvor mussten Sie Variablen verwenden oder eine neue Klasse nur für die Antwort der Funktion erstellen.

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

Egal welchen Weg Sie nehmen, ich denke, Sie sind auf jeden Fall richtig. Sie geben den zwei zusammengepassten Daten eine echte Bedeutung. Das ist ein selbstdokumentierender Code und im Großen und Ganzen direkt in der Struktur des Codes.