В попытке демистификации я буду избегать говорить об итераторах, поскольку они сами могут быть частью тайны.
операторы доходности и разрыва доходности чаще всего используются для обеспечения "отложенной оценки" коллекции.
Это означает, что когда вы получаете значение метода, который использует возвращаемую доходность, коллекция вещей, которые вы пытаетесь получить, еще не существует вместе (по сути, она пуста). По мере их обхода (используя foreach) он будет выполнять метод в это время и получит следующий элемент в перечислении.
Некоторые свойства и методы вызовут одновременную оценку всего перечисления (например, «Подсчет»).
Вот краткий пример разницы между возвратом коллекции и доходностью:
string[] names = { "Joe", "Jim", "Sam", "Ed", "Sally" };
public IEnumerable<string> GetYieldEnumerable()
{
foreach (var name in names)
yield return name;
}
public IEnumerable<string> GetList()
{
var list = new List<string>();
foreach (var name in names)
list.Add(name);
return list;
}
// we're going to execute the GetYieldEnumerable() method
// but the foreach statement inside it isn't going to execute
var yieldNames = GetNamesEnumerable();
// now we're going to execute the GetList() method and
// the foreach method will execute
var listNames = GetList();
// now we want to look for a specific name in yieldNames.
// only the first two iterations of the foreach loop in the
// GetYieldEnumeration() method will need to be called to find it.
if (yieldNames.Contains("Jim")
Console.WriteLine("Found Jim and only had to loop twice!");
// now we'll look for a specific name in listNames.
// the entire names collection was already iterated over
// so we've already paid the initial cost of looping through that collection.
// now we're going to have to add two more loops to find it in the listNames
// collection.
if (listNames.Contains("Jim"))
Console.WriteLine("Found Jim and had to loop 7 times! (5 for names and 2 for listNames)");
Это также можно использовать, если вам нужно получить ссылку на перечисление до того, как исходные данные будут иметь значения. Например, если коллекция имен не была завершена, чтобы начать с:
string[] names = { "Joe", "Jim", "Sam", "Ed", "Sally" };
public IEnumerable<string> GetYieldEnumerable()
{
foreach (var name in names)
yield return name;
}
public IEnumerable<string> GetList()
{
var list = new List<string>();
foreach (var name in names)
list.Add(name);
return list;
}
var yieldNames = GetNamesEnumerable();
var listNames = GetList();
// now we'll change the source data by renaming "Jim" to "Jimbo"
names[1] = "Jimbo";
if (yieldNames.Contains("Jimbo")
Console.WriteLine("Found Jimbo!");
// Because this enumeration was evaluated completely before we changed "Jim"
// to "Jimbo" it isn't going to be found
if (listNames.Contains("Jimbo"))
// this can't be true
else
Console.WriteLine("Couldn't find Jimbo, because he wasn't there when I was evaluated.");