69

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

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

4

5 回答 5

45

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

RangeMiscUtil中有一个您可能感兴趣的类型 - 它确实可以进行简单的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 更恰当地表达日期的概念,但我们目前没有范围之类的东西......这是一个好主意虽然 - 我添加了一个功能请求

于 2009-12-04T08:03:33.127 回答
15

在 .NET 4.0 或更高版本中,添加了 Tuple<> 类型来处理多个值。

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

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

无论您采取哪条路线,我认为您肯定采取了正确的方法。您正在为两个配对的日期赋予真正的意义。那是自我记录的代码,并且以最好的方式,就在代码的结构中。

于 2015-05-28T22:21:27.550 回答
5

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

请注意,没有一个方便的 BCL 构造。

另外 - 想想当你有一个范围时你可以集中的所有美妙的方法(可能还有运算符);“包含”(日期时间?另一个范围?包括/不包括限制?),“相交”,偏移量(时间跨度)等。有一个类型来处理它的明确情况。请注意,在 ORM 级别,如果您的 ORM 支持复合值,这会更容易——我相信 NHibernate 支持,可能还有 EF 4.0。

于 2009-12-04T07:59:50.497 回答
1

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

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

于 2009-12-04T08:12:14.067 回答
0

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

我认为你想要的是相当健全的。

于 2009-12-04T08:01:02.413 回答