我应该制作一个DateRange对象吗?

时间:2009-12-04 07:56:32

标签: .net model tuples date-range

我的一些域对象将日期范围包含为一对开始日期和结束日期属性:

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中有一个。

根据我的经验,使对象层次更深入往往使事情复杂化。这些对象确实被发送到ReportViewer控件显示的RDLC报告,但这是次要的。我会将视图弯曲到模型而不是相反。但是,我们并不依赖于属性名称,并且愿意与以下内容妥协:

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类型污染我的公共领域方法签名感觉非常非常脏。

5 个答案:

答案 0 :(得分:38)

不,你没有错过通用课程。

我在MiscUtil中有Range类型您可能感兴趣 - 这肯定会导致简单的DateTime操作。谈到Marc的回答,我不记得这是一个结构还是一个类 - 当然欢迎你改变它。

由于Marc的泛型恶作剧(假设您使用的是.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
}

(这也是使用一堆扩展方法 - 对于测试比生产更有用。)

为了解决Marc的答案中的另一点,Noda Time肯定能够比.NET API更恰当地表达日期的概念,但我们目前没有像范围那样的东西。 ..虽然这是个好主意 - 我添加了feature request

答案 1 :(得分:9)

在.NET 4.0或更高版本中,元组&lt;&gt;添加了类型以处理多个值。

使用元组类型,您可以动态定义自己的值组合。您的问题很常见,类似于函数想要返回多个值时。以前,您必须使用变量或仅为函数的响应创建一个新类。

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

无论你采取哪种方式,我认为你肯定采取了正确的方法。你正在给两个日期配对的真正含义。这是自我记录的代码,最好的方式是代码结构。

答案 2 :(得分:5)

如果您使用日期做了很多工作,是的 - 范围可以很方便。这实际上是其中一个非常罕见的情况,其中应该可能将其写为struct(不可变)。但请注意,“Noda Time”可能会为您提供所有这些以及更多(当它完成时)。我以前做过调度软件;我有几个这样的结构(略有不同的工作)。

注意,没有方便的BCL结构。

另外 - 想想你拥有一个范围时可以集中的所有精彩方法(以及可能的操作符); “包含”(另一个范围的日期时间?包括/排除限制?),“相交”,偏移(一个时间跨度)等。明确情况下有一个类型来处理它。请注意,在ORM级别,如果您的ORM支持复合值,这会更容易 - 我相信NHibernate会这样做,而且可能是EF 4.0。

答案 3 :(得分:0)

我不知道DateRange性质的任何本机.NET类。最接近的可能是DateTime + TimeSpan或DateTime / DateTime组合。

我认为你想要的是相当合理的。

答案 4 :(得分:0)

正如Mark和Jon已经提到的那样,我会将其创建为值类型,这是不可变的。我会选择将它作为结构实现,并实现IEquatable和IComparable接口。

当使用像NHibernate这样的ORM时,您将能够将值类型存储在表示实体的表中。