2009-12-04 16 views
47

Certains de mes objets de domaine contiennent des plages de dates comme une paire de propriétés de début et de fin:Dois-je créer un objet 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; } 
} 

et je me retrouve avec beaucoup de ceci:

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

Le dernier m'a fait Je me demande ... Dois-je implémenter une classe DateRange? Je n'en connais pas un dans la BCL. Dans mon expérience, compliquer la hiérarchie des objets complique souvent les choses. Ces objets sont envoyés aux rapports RDLC affichés par le contrôle ReportViewer, mais c'est secondaire. Je vais plier la vue au modèle plutôt que vice versa. Nous ne sommes pas liés aux noms de propriétés, bien que, et nous serions prêts à faire des compromis avec quelque chose comme:

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

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

Un avantage d'une classe DateRange serait centralisée validation de la date de fin à venir après la date de début et il simplifiera mes signatures de méthode:

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

Je ne suis pas sûr qu'une classe DateRange ne me attirer plus d'ennuis que sa valeur. Des avis? Question secondaire: Ai-je manqué quelque part une classe générique de tuple générique dans la BCL? Je sais qu'il y en a de très spécifiques qui flottent dans différents espaces de noms. Polluer mes signatures de méthodes de domaine public avec des types C5 est très, très sale.

+0

Je pense vraiment qu'une classe DateRange peut aider. J'ai commencé à écrire le fond pour un moment en arrière: http://www.adamjamesnaylor.com/2012/11/04/C-DateRange-Class.aspx –

+0

@AdamNaylor: Vos liens semblent être en panne ... – testing

Répondre

33

Non, vous n'avez pas manqué une classe polyvalente.

J'ai un Range tapez MiscUtil qui peut vous intéresser - et il fait certainement pour la manipulation DateTime simple. En me référant à la réponse de Marc, je ne me souviens pas s'il s'agit d'une structure ou d'une classe. Bien sûr, vous pouvez le modifier.

Il est agréable et facile de passer à travers, en raison des manigances génériques de Marc (en supposant que vous utilisez .NET 3.5, au moins - c'est faisable avec 2.0 mais pas supporté pour le moment);

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

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

(C'est en utilisant aussi un tas de méthodes d'extension -. Plus utile pour le test de production)

Pour faire face à l'autre point dans la réponse de Marc, Noda Time sera certainement en mesure d'exprimer le concept d'une date de manière plus appropriée que l'API .NET, mais nous n'avons rien de tel qu'une gamme pour le moment ... C'est une bonne idée cependant - j'ai ajouté un feature request.

+0

Désolé si j'ai mal parlé de Noda Time - il semble cependant un excellent choix pour les personnes intéressées par le temps. –

+0

Non, c'est bien - si vous ne l'aviez pas mentionné, je ne sais pas si j'aurais pensé ajouter une demande de fonctionnalité au projet :) Je pense que c'est une exigence assez courante - le peu difficile va fonctionner ce qu'il faut pour accommoder les différents réglages que les gens voudront! –

+9

Syntaxe intéressante. –

5

Si vous faites beaucoup de travail avec les dates, oui - une gamme peut être utile. C'est en fait un de ces cas oh-si-rares où devrait probablement l'écrire comme struct (immuable). Notez, cependant, que "Noda Time" vous donnera probablement tout cela et plus encore (quand il sera complet). J'ai déjà fait un logiciel de planification; J'ai eu quelques structures de ce genre (pour des emplois légèrement différents). Remarque: il n'y a pas de construction BCL très pratique pour cela.

Aussi - pensez à toutes les méthodes merveilleuses (et éventuellement les opérateurs) que vous pouvez centraliser quand vous avez une gamme; "contains" (d'un datetime? d'une autre plage? incluant/excluant des limites?), "intersects", offset-by (un timespan), etc. A défini cas pour avoir un type pour le gérer. Notez qu'au niveau ORM, c'est plus facile si votre ORM supporte les valeurs composites - je pense que NHibernate le fait, et peut-être EF 4.0.

+0

Oh oui , Noda. En attente de cela .... –

+0

Étant donné qu'il s'agit d'un refactoring pour mieux gérer la manipulation des dates et des plages, je suppose qu'il est logique de lui donner une classe. Je voudrais seulement utiliser NHibernate sur ce projet. Toutes ces heures perdues en écrivant un assez bien si je le dis moi-même, mais pâle en comparaison, DAL. Projet suivant, cependant. Je joue avec pour le moment. –

0

Je ne connais aucune classe .NET native de la nature DateRange. La plus proche est probablement DateTime + TimeSpan ou DateTime/DateTime.

Je pense que ce que vous voulez est assez solide.

0

Comme Mark et Jon l'ont déjà mentionné, je créerais ceci comme un type de valeur, qui est immuable. J'opterais pour l'implémenter en tant que struct, et implémenterais les interfaces IEquatable et IComparable. Lorsque vous utilisez un ORM comme NHibernate, vous pouvez stocker le type de valeur dans une table qui représente une entité.

+0

Donc, il ne devrait pas être difficile d'avoir un sous-objet DateRange mais garder la structure de la table plate avec les colonnes Date et Fin en utilisant NHibernate (Fluent)? Je ne le pense pas, mais il est bon de savoir à l'avance. –

+0

Vous pouvez implémenter votre DateRange en tant qu'objet valeur et l'utiliser dans NHibernate en tant que 'composant'. Ensuite, vous pouvez en effet conserver la structure de la table à plat avec des colonnes de date de début et de fin. –

5

Dans .NET 4.0 ou supérieur, le type Tuple <> a été ajouté pour gérer plusieurs valeurs.

Avec le type de ligne, vous pouvez définir votre propre combinaison de valeurs à la volée. Votre problème est très commun et est similaire à lorsqu'une fonction veut renvoyer plusieurs valeurs. Auparavant, vous deviez utiliser des variables externes ou créer une nouvelle classe juste pour la réponse de la fonction. Quel que soit le chemin que vous empruntez, je pense que vous prenez définitivement la bonne approche. Vous donnez un sens réel à ce que sont deux dates jumelées. C'est du code auto-documenté et de la meilleure façon, juste dans la structure du code.