产量很有用,因为它可以节省空间。编程中的大多数优化都在空间(磁盘、内存、网络)和处理之间进行权衡。Yield 作为一种编程结构,允许您按顺序对集合进行多次迭代,而无需为每次迭代创建单独的集合副本。
考虑这个例子:
static IEnumerable<Person> GetAllPeople()
{
return new List<Person>()
{
new Person() { Name = "George", Surname = "Bush", City = "Washington" },
new Person() { Name = "Abraham", Surname = "Lincoln", City = "Washington" },
new Person() { Name = "Joe", Surname = "Average", City = "New York" }
};
}
static IEnumerable<Person> GetPeopleFrom(this IEnumerable<Person> people, string where)
{
foreach (var person in people)
{
if (person.City == where) yield return person;
}
yield break;
}
static IEnumerable<Person> GetPeopleWithInitial(this IEnumerable<Person> people, string initial)
{
foreach (var person in people)
{
if (person.Name.StartsWith(initial)) yield return person;
}
yield break;
}
static void Main(string[] args)
{
var people = GetAllPeople();
foreach (var p in people.GetPeopleFrom("Washington"))
{
// do something with washingtonites
}
foreach (var p in people.GetPeopleWithInitial("G"))
{
// do something with people with initial G
}
foreach (var p in people.GetPeopleWithInitial("P").GetPeopleFrom("New York"))
{
// etc
}
}
(显然,您不需要将 yield 与扩展方法一起使用,它只是创建了一个强大的范式来思考数据。)
如您所见,如果您有很多这些“过滤器”方法(但它可以是任何一种对人员列表执行某些工作的方法),您可以将其中的许多链接在一起,而无需为每个步骤提供额外的存储空间. 这是提高编程语言 (C#) 以更好地表达您的解决方案的一种方法。
yield 的第一个副作用是它会延迟过滤逻辑的执行,直到您真正需要它。因此,如果您创建了一个 IEnumerable<> 类型的变量(带有产量)但从不迭代它,那么您永远不会执行逻辑或消耗空间,这是一种强大且免费的优化。
另一个副作用是 yield 在最低的公共集合接口 (IEnumerable<>) 上运行,它可以创建具有广泛适用性的类库代码。