C#:foreach 中的yield return 失败 - 主体不能是迭代器块

发布于 2024-08-24 17:05:20 字数 826 浏览 9 评论 0原文

考虑一下这段混淆的代码。目的是通过匿名构造函数动态创建一个新对象并yield 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

Consider this bit of obfuscated code. The intention is to create a new object on the fly via the anonymous constructor and yield return it. The goal is to avoid having to maintain a local collection just to simply return it.

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

Unfortunately, this bit of code produces an exception:

Error 28 The body of 'Foo.BuildComputerAssets()' cannot be an iterator block because 'System.Collections.Generic.List' is not an iterator interface type

Questions

  • What does this error message mean?
  • How can I avoid this error and use yield return properly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

热血少△年 2024-08-31 17:05:20

您只能在返回 IEnumerableIEnumerator 而不是 List 的函数中使用 yield return >。

您需要更改函数以返回 IEnumerable

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

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

You can only use yield return in a function that returns an IEnumerable or an IEnumerator, not a List<T>.

You need to change your function to return an IEnumerable<DesktopComputer>.

Alternatively, you can rewrite the function to use List<T>.ConvertAll:

return GetComputerIdTags().ConvertAll(pcTag => 
    new DesktopComputer() {
        AssetTag    = pcTag,
        Description = "PC " + pcTag,
        AcquireDate = DateTime.Now
    });
唠甜嗑 2024-08-31 17:05:20

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

public static IEnumerable<DesktopComputer> BuildComputerAssets()

Your method signature is wrong. It should be:

public static IEnumerable<DesktopComputer> BuildComputerAssets()
浪漫人生路 2024-08-31 17:05:20

yield 仅适用于迭代器类型:

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

迭代器 定义为

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

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

yield only works on Iterator types:

The yield statement can only appear inside an iterator block

Iterators are defined as

The return type of an iterator must be IEnumerable, IEnumerator, IEnumerable<T>, or IEnumerator<T>.

IList and IList<T> do implement IEnumerable/IEnumerable<T>, but every caller to an enumerator expects one of the four types above and none else.

ゃ人海孤独症 2024-08-31 17:05:20

您还可以使用 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)。

You could also implement the same functionality using a LINQ query (in C# 3.0+). This is less efficient than using ConvertAll method, but it is more general. Later, you may also need to use other LINQ features such as filtering:

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

The ToList method converts the result from IEnumerable<T> to List<T>. I personally don't like ConvertAll, because it does the same thing as LINQ. But because it was added earlier, it cannot be used with LINQ (it should have been called Select).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文