The type constraint on
T B ensures that we??™ll be able to compare two values, and we perform an executiontime
check to prevent a range being constructed with a lower bound higher than the
upper bound C. We still need to work around the problem of implementing both
IEnumerable
and IEnumerable by using explicit interface implementation for the
nongeneric type E and exposing the generic interface implementation in the more
usual, implicit way D. If you don??™t immediately see why this is necessary, look back to
the descriptions in sections 2.2.2 and 3.4.3.
The actual iteration merely starts with the lower end of the range, and repeatedly
fetches the next value by calling the abstract GetNextValue method F until we??™ve
reached or exceeded the top of the range. If the last value found is in the range, we
yield that as well. Note that the GetNextValue method shouldn??™t need to keep any
state??”given one value, it should merely return the next one in the range. This is useful
as it means that we should be able to make most of the derived types immutable,
which is always nice. It??™s easy to derive from Range, and we??™ll implement the two
examples given earlier??”a range for dates and times (DateTimeRange) and a range
for integers (Int32Range). They??™re very short and very similar??”listing 6.9 shows both
of them together.
using System;
public class DateTimeRange : Range
{
readonly TimeSpan step;
public DateTimeRange(DateTime start, DateTime end)
: this (start, end, TimeSpan.
Pages:
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353