考虑一下混淆代码。目的是通过匿名构造函数和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
?答案 0 :(得分:52)
您只能在返回yield return
或IEnumerable
而不是IEnumerator
的函数中使用List<T>
。
您需要更改功能以返回IEnumerable<DesktopComputer>
。
或者,您可以重写函数以使用List<T>.ConvertAll
:
return GetComputerIdTags().ConvertAll(pcTag =>
new DesktopComputer() {
AssetTag = pcTag,
Description = "PC " + pcTag,
AcquireDate = DateTime.Now
});
答案 1 :(得分:17)
您的方法签名错误。它应该是:
public static IEnumerable<DesktopComputer> BuildComputerAssets()
答案 2 :(得分:8)
yield仅适用于迭代器类型:
yield语句只能出现在迭代器块
中
Iterators定义为
迭代器的返回类型必须是IEnumerable,IEnumerator,IEnumerable&lt; T&gt;或IEnumerator&lt; T&gt;。
IList和IList&lt; T&gt;确实实现IEnumerable / IEnumerable&lt; T&gt;,但枚举器的每个调用者都需要上述四种类型中的一种,而不是其他类型。
答案 3 :(得分:2)
您还可以使用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<T>
转换为List<T>
。我个人不喜欢ConvertAll
,因为它与LINQ做同样的事情。但是因为它是之前添加的,所以它不能与LINQ一起使用(它应该被称为Select
)。