我试图打印2013年开始的日期1 1结束2015 1 1独家。
问题是在当前之前调用MoveNext所以它在2013年开始打印2 1.我的问题是1).NET中是否存在某种类型的Range类?我只知道enumerable.range并不接近我的需要。 2)使用bool hasStarted
并在MoveNext中检查它是最常用的来解决我的问题吗?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DateTest
{
class Program
{
static void Main(string[] args)
{
foreach (var m in Range.Create(new DateTime(2013, 1, 1), new DateTime(2015, 1, 1), s => s.AddMonths(1)))
Console.WriteLine(m);
}
}
static class Range { public static Range<T> Create<T>(T s, T e, Func<T, T> inc) where T : IComparable<T> { return new Range<T>(s, e, inc); } }
class Range<T> : IEnumerable<T>, IEnumerator<T> where T : IComparable<T>
{
T start, pos, end;
Func<T,T> inc;
public Range(T s, T e, Func<T,T> inc) { pos=start= s; end = e; this.inc = inc; }
public T Current
{
get { return pos; }
}
public void Dispose()
{
//throw new NotImplementedException();
}
object System.Collections.IEnumerator.Current
{
get { return pos; }
}
public bool MoveNext()
{
pos = inc(pos);
return pos.CompareTo(end) < 0;
}
public void Reset()
{
pos = start;
}
public IEnumerator<T> GetEnumerator()
{
return this;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this;
}
}
}
答案 0 :(得分:3)
我可能会重构代码,这样我就不必自己写MoveNext()
和Current
了:
class Range<T> : IEnumerable<T> where T : IComparable<T>
{
// other stuff...
public IEnumerator<T> GetEnumerator()
{
for (T val = start; val.CompareTo(end) < 0; val = inc(val))
yield return val;
}
}
有关其工作原理的详情,请参阅yield
keyword documentation。
答案 1 :(得分:1)
你可以使用迭代器:
class Range<T> : IEnumerable<T> where T : IComparable<T>
{
T start, pos, end;
Func<T, T> inc;
public Range(T s, T e, Func<T, T> inc) { pos = start = s; end = e; this.inc = inc; }
public IEnumerator<T> GetEnumerator()
{
T current = start;
while (current.CompareTo(end) < 0)
{
yield return current;
current = inc(current);
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
您可以完全删除Range<T>
类并直接在静态Range.Create
方法中实现迭代器。
答案 2 :(得分:0)
这是yield return
无法创建自己的自定义IEnumerable的情况,正如我在this blog post中所描述的那样:
public static IEnumerable<DateTime> DaysInRange(DateTime startDate, DateTime endDate)
{
DateTime current = startDate;
while (current <= endDate)
{
yield return current;
current = current.AddDays(1);
}
}
答案 3 :(得分:0)
您可以使用stock Enumerable.Range()
方法获得所需内容(可枚举的日期列表),因此:
DateTime dtFrom = new DateTime(2013,1,1) ;
DateTime dtThru = new DateTime(2015,1,1) ;
DateTime[] dates = Enumerable.Range( 0 , (dtThru-dtFrom).Days )
.Select( x => dtFrom.AddDays(x) )
.ToArray()
;
或者您可以使用自己的可枚举DateRange()
方法。像这样的东西会起作用。首先是一个枚举来指定间隔的大小(有一个可用,但你必须通过Microsoft.VisualBasic
命名空间来吸收整个VB运行时才能得到它.Woof。):
public enum DateTimeInterval
{
Day = 1 ,
Week = 2 ,
Month = 3 ,
Year = 4 ,
}
然后是一个简单的可枚举方法:
public static IEnumerable<DateTime> DateRange( DateTime dateFrom , DateTime dateThru , DateTimeInterval interval , int increment )
{
if ( increment < 1 ) throw new ArgumentOutOfRangeException("increment");
for( DateTime date = dateFrom.Date ; date <= dateThru ; )
{
yield return date ;
switch (interval )
{
case DateTimeInterval.Day : date = date.AddDays( increment ) ; break ;
case DateTimeInterval.Week : date = date.AddDays( increment*7 ) ; break ;
case DateTimeInterval.Month : date = date.AddMonths( increment ) ; break ;
case DateTimeInterval.Year : date = date.AddYears( increment ) ; break ;
default : throw new ArgumentOutOfRangeException("interval") ;
}
}
}