这是我的方法:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
它工作正常,但我想我可以写一些像这样清洁的东西:
static IEnumerable<DateTime> GetMonths(DateTime from, DateTime to)
{
TimeSpan logsMissingTimespan = to - from;
if (logsMissingTimespan == new TimeSpan(0))
{
yield break;
}
return GetMonthsBetweenTwoDates(from, to);
}
Run Code Online (Sandbox Code Playgroud)
但是我有一条错误消息:
无法从迭代器返回值.使用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>();
}
Run Code Online (Sandbox Code Playgroud)
因为你已经使用了yield它,所以现在希望该方法一次产生一个元素.它必须每次迭代只能使用yeild return或yield break返回一个元素.
你应该使用Enumerable.Empty<DateTime>();而不是yield break.
前两个示例的形式会产生不同类型的输出。
如果满足条件,您的第一个示例将IEnumerable<T>直接返回,如果不满足,则返回空引用。您的第二个示例始终返回 an IEnumerable<T>,但条件确定它是否包含任何元素。
第二个示例是通过使用迭代器块完成的。yieldC# 编译器使用该语法将您编写的函数转换为实现的自定义(隐藏)类型IEnumerable<T>和实现IEnumerator<T>. 这些类型实现必要的状态机,以实现(希望)您放入函数中的逻辑。正因为如此,你不能混合范例;您必须IEnumerable<T>从函数返回一个实例(并且根本不在yield任何地方使用),或者所有内容都必须通过返回yield。
如果您所关心的只是返回空引用这一事实,则可以通过返回Enumerable.Empty<DateTime>而不是 来使方法在语义上相同null。