C#: уступите возврат в foreach перестал работать - тело не может быть блоком итератора

Рассмотрите этот бит запутываемого кода. Намерение состоит в том, чтобы создать новый объект на лету через анонимного конструктора и yield return это. Цель состоит в том, чтобы избежать необходимости поддерживать локальный набор только только к return это.

public static List<DesktopComputer> BuildComputerAssets()
{           
    List<string> idTags = GetComputerIdTags();

    foreach (var pcTag in idTags)
    {
        yield return new DesktopComputer() {AssetTag= pcTag
                                          , Description = "PC " + pcTag
                                          , AcquireDate = DateTime.Now
                                           };
    }            
}

К сожалению, этот бит кода производит исключение:

Ошибка 28 тело 'Нечто. BuildComputerAssets ()' не может быть блоком итератора потому что 'Система. Наборы. Универсальный. Список' не является типом интерфейса итератора

Вопросы

  • Что означает это сообщение об ошибке?
  • Как я могу избежать этой ошибки и использования yield return правильно?
42
задан p.campbell 10 March 2010 в 01:12
поделиться

4 ответа

Вы можете использовать yield return только в функции, которая возвращает IEnumerable или IEnumerator , но не List .

Вам нужно изменить свою функцию, чтобы она возвращала IEnumerable .

В качестве альтернативы вы можете переписать функцию для использования List .ConvertAll :

return GetComputerIdTags().ConvertAll(pcTag => 
    new DesktopComputer() {
        AssetTag    = pcTag,
        Description = "PC " + pcTag,
        AcquireDate = DateTime.Now
    });
53
ответ дан 26 November 2019 в 23:42
поделиться

Вы также можете реализовать ту же функциональность с помощью запроса LINQ (в C # 3.0+). Это менее эффективно, чем использование метода ConvertAll , но является более общим. Позже вам также может потребоваться использовать другие функции LINQ, такие как фильтрация:

return (from pcTag in GetComputerIdTags()
        select new DesktopComputer() { 
          AssetTag    = pcTag, 
          Description = "PC " + pcTag, 
          AcquireDate = DateTime.Now 
        }).ToList();

Метод ToList преобразует результат из IEnumerable в List . Мне лично не нравится ConvertAll , потому что он выполняет то же самое, что и LINQ. Но поскольку он был добавлен ранее, его нельзя использовать с LINQ (он должен был называться Select ).

2
ответ дан 26 November 2019 в 23:42
поделиться

Ваша подпись метода неверна. Это должно быть:

public static IEnumerable<DesktopComputer> BuildComputerAssets()
17
ответ дан 26 November 2019 в 23:42
поделиться

yield работает только с типами итераторов:

Оператор yield может появиться только внутри блока итераторов

Итераторы определяются как

Возвращаемый тип итератора должен быть IEnumerable, IEnumerator, IEnumerable или IEnumerator.

IList и IList реализуют IEnumerable/IEnumerable, но каждый вызывающий перечислитель ожидает один из четырех вышеперечисленных типов и никакой другой.

8
ответ дан 26 November 2019 в 23:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: