这是我的方法:
static IEnumerable<DateTime> GetMonths(DateTime from, DateTime to)
{
// if logs is not uptodate
TimeSpan logsMissingTimespan = to - from;
if (logsMissingTimespan != new TimeSpan(0))
{
return GetMonthsBetweenTwoDates(from, to);
}
return null; // Why this line ?
}
private static IEnumerable<DateTime> GetMonthsBetweenTwoDates(DateTime from, DateTime to)
{
DateTime date = from;
DateTime lastDate = DateTime.MaxValue;
while (date < to)
{
if (lastDate.Month != date.Month)
{
lastDate = date;
yield return lastDate;
}
date = date.AddDays(1);
}
}
它工作正常,但我想我可以写一些像这样清洁的东西:
static IEnumerable<DateTime> GetMonths(DateTime from, DateTime to)
{
TimeSpan logsMissingTimespan = to - from;
if (logsMissingTimespan == new TimeSpan(0))
{
yield break;
}
return GetMonthsBetweenTwoDates(from, to);
}
但我有一条错误消息:
无法从迭代器返回值。使用yield return语句返回一个值,或者使用yield break来结束迭代。
为什么我应该有return null
以及正确的语法?
编辑:
所以,正确的方法是使用Enumerable.Empty:
static IEnumerable<DateTime> GetMonths(DateTime from, DateTime to)
{
// if logs is not uptodate
TimeSpan logsMissingTimespan = to - from;
if (logsMissingTimespan != new TimeSpan(0))
{
return GetMonthsBetweenTwoDates(from, to);
}
return Enumerable.Empty<DateTime>();
}
答案 0 :(得分:5)
因为您使用了单词yield
,所以它现在希望该方法一次产生一个元素。它必须仅使用yeild return
或yield break
每次迭代返回一个元素。
您应该使用Enumerable.Empty<DateTime>();
代替yield break
。
答案 1 :(得分:3)
一个方法是用迭代器块实现的,或者不是 - 所以所有都是yield return
和yield break
,或者都不是。
但是,你 不需要做任何特别的事情。您的原始GetMonthsBetweenTwoDates
已经在to == from
处工作,因为它永远不会进入while循环。
另一方面,您对lastDate
的使用看起来很可疑 - 特别是,如果from
碰巧与{{1}同一个月,它看起来会有所不同}}。
答案 2 :(得分:3)
前两个示例的形式会产生不同类型的输出。
如果满足条件,您的第一个示例将直接返回IEnumerable<T>
,如果不满足,则返回空引用。您的第二个示例始终返回IEnumerable<T>
,但条件确定它是否包含任何元素。
第二个例子是使用迭代器块完成的。 C#编译器使用yield
语法将您编写的函数转换为实现IEnumerable<T>
的自定义(隐藏)类型和实现IEnumerator<T>
的类型。这些类型实现了必要的状态机,以实现(希望)您放入函数的逻辑。因此,你不能混淆范式;您必须从函数返回IEnumerable<T>
的实例(而不是在任何地方使用yield
),或者必须通过yield
返回所有内容。
如果你所关心的只是你要返回一个空引用,那么你可以通过返回Enumerable.Empty<DateTime>
而不是null
来使方法在语义上相同。
答案 3 :(得分:0)
在第一次检查时,您不需要屈服中断来结束迭代。
if (logsMissingTimespan == new TimeSpan(0))
{
return null;
}
return GetMonthsBetweenTwoDates(from, to);