迭代器块的正确用法
本文关键字:用法 迭代器 | 更新日期: 2023-09-27 18:23:59
我之前重构了一些代码,遇到了一个我不太确定的迭代器块的实现。在系统的集成层中,客户端正在为某些数据调用外部API,我有一组翻译器,它们将从API返回的数据转换为逻辑层中使用的业务实体集合。一个常见的翻译器类如下所示:
// translate a collection of entities coming back from an extrernal source into business entities
public static IEnumerable<MyBusinessEnt> Translate(IEnumerable<My3rdPartyEnt> ents) {
// for each 3rd party ent, create business ent and return collection
return from ent in ents
select new MyBusinessEnt {
Id = ent.Id,
Code = ent.Code
};
}
今天我遇到了以下代码。同样,它是一个转换器类,其目的是将参数中的集合转换为方法返回类型。然而,这一次它是一个迭代器块:
// same implementation of a translator but as an iterator block
public static IEnumerable<MyBusinessEnt> Translate(IEnumerable<My3rdPartyEnt> ents) {
foreach(var ent in ents)
{
yield return new MyBusinessEnt {
Id = ent.Id,
Code = ent.Code
};
}
}
我的问题是:这是迭代器块的有效使用吗?我看不出以这种方式创建翻译类有什么好处。这会导致一些意想不到的行为吗
您的两个样本做的事情几乎完全相同。查询版本将被重写为对Select的调用,Select的编写方式与第二个示例完全相同;它对源集合中的每个元素进行迭代,并返回一个转换后的元素。
这是对迭代器块的一种非常有效的使用,当然不再需要像这样编写自己的迭代器区块,因为您只需要使用Select
。
是的,这是有效的。foreach
具有可调试的优点,所以我倾向于使用这种设计。
第一个例子不是迭代器。它只是创建并返回一个IEnumerable<MyBusinessEnt>
。
第二个是迭代器,我认为它没有任何问题。每次调用方迭代该方法的返回值时,yield
都会返回一个新元素。
是的,这很好,结果非常相似。
两者都创建了一个能够返回结果的对象。两者都依赖于可枚举的源保持完整,直到结果完成(或缩短)。两者都使用延迟执行,即在迭代结果时一次创建一个对象。
不同之处在于,第一个返回使用库方法生成枚举器的表达式,而第二个创建自定义枚举器。
每个代码运行时,的主要区别在上第一个延迟到迭代返回值,而第二个立即运行我的意思是for循环正在强制运行迭代。该类公开了一个IEnumerable<T>
,并且在这种情况下被延迟,这是另一回事。
这与简单的Select
相比没有任何好处。yield
的真正力量是当涉及一个条件时:
foreach(var ent in ents)
{
if(someCondition)
yield return new MyBusinessEnt {
Id = ent.Id,
Code = ent.Code
};
}