C#:foreach中的收益返回失败-主体不能为迭代器b

考虑一下这段混淆的代码。 目的是通过匿名构造函数动态创建一个新对象,然后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'Foo.BuildComputerAssets()'的正文不能是迭代器块,因为'System.Collections.Generic.List'不是迭代器接口类型

问题

  • 此错误消息是什么意思?
  • 如何避免此错误并正确使用yield return
p.campbell asked 2020-08-11T01:42:51Z
4个解决方案
53 votes

您只能在返回IEnumerableIEnumerator而不返回List<T>的函数中使用List<T>.ConvertAll

您需要更改函数以返回List<T>.ConvertAll

或者,您可以重写该函数以使用List<T>.ConvertAll

return GetComputerIdTags().ConvertAll(pcTag => 
    new DesktopComputer() {
        AssetTag    = pcTag,
        Description = "PC " + pcTag,
        AcquireDate = DateTime.Now
    });
SLaks answered 2020-08-11T01:43:06Z
17 votes

您的方法签名错误。 它应该是:

public static IEnumerable<DesktopComputer> BuildComputerAssets()
Brian Genisio answered 2020-08-11T01:43:25Z
8 votes

yield仅适用于Iterator类型:

yield语句只能出现在迭代器块内

迭代器定义为

迭代器的返回类型必须为IEnumerable,IEnumerator,IEnumerable <T>或IEnumerator <T>。

IList和IList <T>确实实现了IEnumerable / IEnumerable <T>,但是枚举器的每个调用者都期望上面四种类型之一,而没有其他。

Michael Stum answered 2020-08-11T01:44:03Z
2 votes

您还可以使用LINQ查询(在C#3.0+中)实现相同的功能。 与使用ToList方法相比,这效率较低,但更为通用。 以后,您可能还需要使用其他LINQ功能,例如过滤:

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

ToList方法将结果从IEnumerable<T>转换为List<T>。我个人不喜欢ConvertAll,因为它的作用与LINQ相同。 但是因为它是以前添加的,所以它不能与LINQ一起使用(它应该被称为Select)。

Tomas Petricek answered 2020-08-11T01:44:28Z
translate from https://stackoverflow.com:/questions/2413851/c-yield-return-within-a-foreach-fails-body-cannot-be-an-iterator-block