语法问题使用yield return的IEnumerable <T>方法

Flo*_*ian 6 c# yield-return

这是我的方法:

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)

Dav*_*haw 5

因为你已经使用了yield它,所以现在希望该方法一次产生一个元素.它必须每次迭代只能使用yeild returnyield break返回一个元素.

你应该使用Enumerable.Empty<DateTime>();而不是yield break.


Ada*_*son 4

前两个示例的形式会产生不同类型的输出。

如果满足条件,您的第一个示例将IEnumerable<T>直接返回,如果不满足,则返回空引用。您的第二个示例始终返回 an IEnumerable<T>,但条件确定它是否包含任何元素。

第二个示例是通过使用迭代器块完成的。yieldC# 编译器使用该语法将您编写的函数转换为实现的自定义(隐藏)类型IEnumerable<T>和实现IEnumerator<T>. 这些类型实现必要的状态机,以实现(希望)您放入函数中的逻辑。正因为如此,你不能混合范例;您必须IEnumerable<T>从函数返回一个实例(并且根本不在yield任何地方使用),或者所有内容都必须通过返回yield

如果您所关心的只是返回空引用这一事实,则可以通过返回Enumerable.Empty<DateTime>而不是 来使方法在语义上相同null