【问题标题】:C#: yield return within a foreach fails - body cannot be an iterator blockC#:foreach 中的 yield return 失败 - body 不能是迭代器块
【发布时间】:2011-01-25 17:04:08
【问题描述】:

考虑一下这段混淆的代码。目的是通过匿名构造函数和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

【问题讨论】:

    标签: c# iterator yield


    【解决方案1】:

    您还可以使用 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&lt;T&gt; 转换为List&lt;T&gt;。我个人不喜欢ConvertAll,因为它和LINQ 做同样的事情。但是因为是之前添加的,所以不能和LINQ一起使用(应该叫Select)。

    【讨论】:

      【解决方案2】:

      yield 仅适用于迭代器类型:

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

      Iterators 定义为

      迭代器的返回类型必须是 IEnumerable、IEnumerator、IEnumerable 或 IEnumerator

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

      【讨论】:

        【解决方案3】:

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

        public static IEnumerable<DesktopComputer> BuildComputerAssets()
        

        【讨论】:

          【解决方案4】:

          您只能在返回IEnumerableIEnumerator 而不能返回List&lt;T&gt; 的函数中使用yield return

          您需要更改函数以返回 IEnumerable&lt;DesktopComputer&gt;

          或者,您可以重写函数以使用List&lt;T&gt;.ConvertAll

          return GetComputerIdTags().ConvertAll(pcTag => 
              new DesktopComputer() {
                  AssetTag    = pcTag,
                  Description = "PC " + pcTag,
                  AcquireDate = DateTime.Now
              });
          

          【讨论】:

          猜你喜欢
          • 2011-07-16
          • 2010-11-08
          • 2016-04-24
          • 2022-01-15
          • 1970-01-01
          • 2012-11-14
          • 2011-09-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多