C#:foreach中的yield返回失败 – body不能是一个迭代器块

考虑这一点混淆的代码。 其目的是通过匿名构造函数即时创build一个新对象,并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 }; } } 

不幸的是,这段代码产生了一个exception:

错误28“Foo.BuildComputerAssets()”的主体不能是迭代器块,因为“System.Collections.Generic.List”不是迭代器接口types

问题

  • 这个错误信息是什么意思?
  • 我怎样才能避免这个错误,并正确使用yield return

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

你需要改变你的函数返回一个IEnumerable<DesktopComputer>

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

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

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

 public static IEnumerable<DesktopComputer> BuildComputerAssets() 

yield只能用于Iteratortypes:

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

迭代器被定义为

迭代器的返回types必须是IEnumerable,IEnumerator,IEnumerable <T>或IEnumerator <T>。

IList和IList <T>确实实现了IEnumerable / IEnumerable <T>,但是每个枚举器的调用者都需要上述四种types之一。

您还可以使用LINQ查询(在C#3.0 +中)实现相同的function。 这比使用ConvertAll方法效率更低,但是更一般。 稍后,您可能还需要使用其他LINQfunction,如过滤:

 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 )。