Синтаксическая проблема IEnumerable <T>метод, использующий возвращение доходности - PullRequest
6 голосов
/ 29 ноября 2011

Вот мой метод:

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>();
}

Ответы [ 4 ]

5 голосов
/ 29 ноября 2011

Поскольку вы использовали слово yield, теперь он ожидает, что метод даст по одному элементу за раз. Он должен использовать только yeild return или yield break для возврата одного элемента за итерацию.

Вы должны использовать Enumerable.Empty<DateTime>(); вместо yield break.

3 голосов
/ 29 ноября 2011

Формы ваших первых двух примеров дают разные виды вывода.

Ваш первый пример возвращает IEnumerable<T> напрямую, если условие выполнено, и нулевую ссылку, если это не так. Ваш второй пример всегда возвращает IEnumerable<T>, но условие определяет, есть ли в нем какие-либо элементы.

Второй пример сделан с использованием блока итератора . Синтаксис yield используется компилятором C # для преобразования написанной вами функции в пользовательский (скрытый) тип, реализующий IEnumerable<T>, и тип, реализующий IEnumerator<T>. Эти типы реализуют необходимые конечные автоматы для достижения (надеюсь) логики, которую вы поместили в функцию. Из-за этого вы не можете смешивать парадигмы; вы должны либо вернуть экземпляр функции IEnumerable<T> из функции (и вообще нигде не использовать yield), либо все должно быть возвращено через yield.

Если все, что вас беспокоит, это то, что вы возвращаете нулевую ссылку, вы можете сделать методы семантически одинаковыми, возвращая Enumerable.Empty<DateTime> вместо null.

3 голосов
/ 29 ноября 2011

Метод реализуется либо с помощью блока итератора, либо нет - так что либо все соответствует yield return и yield break, либо ничего из этого.

ОднакоВам не нужно , нужно , чтобы сделать что-то особенное.Ваш исходный GetMonthsBetweenTwoDates уже работает там, где to == from, потому что он никогда не войдет в цикл while.

С другой стороны, использование lastDate мне кажется подозрительным - в частности, похожевсе будет иначе, если from окажется в том же месяце, что и DateTime.MaxValue.

0 голосов
/ 29 ноября 2011

вам не нужен разрыв доходности для завершения итерации при первой проверке.

if (logsMissingTimespan == new TimeSpan(0))
{
    return null;
}    
return GetMonthsBetweenTwoDates(from, to);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...