class Program { static async Task Main(string[] args) { // 堆代码 duidaima.com foreach (int i in ProduceEvenNumbers(9)) { ConsoleExt.Write($"{i}-Main"); } ConsoleExt.Write($"--Main-循环结束"); Console.ReadLine(); } static IEnumerable<int> ProduceEvenNumbers(int upto) { for (int i = 0; i <= upto; i += 2) { ConsoleExt.Write($"{i}-ProduceEvenNumbers"); yield return i; ConsoleExt.Write($"{i}-ProduceEvenNumbers-yielded"); } ConsoleExt.Write($"--ProduceEvenNumbers-循环结束"); } } public static class ConsoleExt { public static void Write(object message) { Console.WriteLine($"(Time: {DateTime.Now.ToString("HH:mm:ss.ffffff")}, Thread {Thread.CurrentThread.ManagedThreadId}): {message} "); } public static void WriteLine(object message) { Console.WriteLine($"(Time: {DateTime.Now.ToString("HH:mm:ss.ffffff")}, Thread {Thread.CurrentThread.ManagedThreadId}): {message} "); } public static async void WriteLineAsync(object message) { await Task.Run(() => Console.WriteLine($"(Time: {DateTime.Now.ToString("HH:mm:ss.ffffff")}, Thread {Thread.CurrentThread.ManagedThreadId}): {message} ")); } }输出结果如下,可见整个循环是单线程运行,ProduceEvenNumbers()生产一个,然后Main()就操作一个,Main() 执行一次操作后,线程返回生产线,继续沿着 return 往后执行;生产线循环结束后,Main() 也接着结束:
class Program { static void Main() { ConsoleExt.Write(string.Join(" ", TakeWhilePositive(new[] { 2, 3, 4, 5, -1, 3, 4 }))); ConsoleExt.Write(string.Join(" ", TakeWhilePositive(new[] { 9, 8, 7 }))); Console.ReadLine(); } static IEnumerable<int> TakeWhilePositive(IEnumerable<int> numbers) { foreach (int n in numbers) { if (n > 0) // 遇到负数就中断循环 { yield return n; } else { yield break; } } } } public static class ConsoleExt { public static void Write(object message) { Console.WriteLine($"(Time: {DateTime.Now.ToString("HH:mm:ss.ffffff")}, Thread {Thread.CurrentThread.ManagedThreadId}): {message} "); } public static void WriteLine(object message) { Console.WriteLine($"(Time: {DateTime.Now.ToString("HH:mm:ss.ffffff")}, Thread {Thread.CurrentThread.ManagedThreadId}): {message} "); } public static async void WriteLineAsync(object message) { await Task.Run(() => Console.WriteLine($"(Time: {DateTime.Now.ToString("HH:mm:ss.ffffff")}, Thread {Thread.CurrentThread.ManagedThreadId}): {message} ")); } }输出结果,第一个数组中第五个数为负数,因此至此就中断循环,包括它自己之后的数字不再返回:
class Program { public static async Task Main() { await foreach (int n in GenerateNumbersAsync(5)) { ConsoleExt.Write(n); } Console.ReadLine(); } static async IAsyncEnumerable<int> GenerateNumbersAsync(int count) { for (int i = 0; i < count; i++) { yield return await ProduceNumberAsync(i); } } static async Task<int> ProduceNumberAsync(int seed) { await Task.Delay(1000); return 2 * seed; } } public static class ConsoleExt { public static void Write(object message) { Console.WriteLine($"(Time: {DateTime.Now.ToString("HH:mm:ss.ffffff")}, Thread {Thread.CurrentThread.ManagedThreadId}): {message} "); } public static void WriteLine(object message) { Console.WriteLine($"(Time: {DateTime.Now.ToString("HH:mm:ss.ffffff")}, Thread {Thread.CurrentThread.ManagedThreadId}): {message} "); } public static async void WriteLineAsync(object message) { await Task.Run(() => Console.WriteLine($"(Time: {DateTime.Now.ToString("HH:mm:ss.ffffff")}, Thread {Thread.CurrentThread.ManagedThreadId}): {message} ")); } }输出结果如下,可见输出的结果有不同线程执行:
class Program { public static void Main() { var ints = new int[] { 1, 2, 3 }; var enumerable = new MyEnumerable<int>(ints); foreach (var item in enumerable) { Console.WriteLine(item); } Console.ReadLine(); } } public class MyEnumerable<T> : IEnumerable<T> { private T[] items; public MyEnumerable(T[] ts) { this.items = ts; } public void Add(T item) { int num = this.items.Length; this.items[num + 1] = item; } public IEnumerator<T> GetEnumerator() { foreach (var item in this.items) { yield return item; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }1.5 不能使用 yield 的情况
public static IEnumerable<int> enumerableFuc() { yield return 1; yield return 2; yield return 3; } // 使用惰性枚举 foreach (var number in enumerableFuc()) { Console.WriteLine(number); }在上面的示例中,GetNumbers() 方法通过yield关键字返回一个 IEnumerable 对象。当我们使用 foreach 循环迭代这个对象时,每次循环都会调用 MoveNext() 方法,并执行到下一个 yield 语句处,返回一个元素。这样就实现了按需生成枚举的元素,而不需要一次性生成所有元素。
static async Task Main(string[] args) { // 用 while (enumerator.MoveNext()) // 代替 foreach(int item in enumerableFuc()) IEnumerator<int> enumerator = enumerableFuc().GetEnumerator(); while (enumerator.MoveNext()) { int current = enumerator.Current; Console.WriteLine(current); } Console.ReadLine(); } // 一个返回类型为 IEnumerable<int>,其中包含三个 yield return public static IEnumerable<int> enumerableFuc() { Console.WriteLine("enumerableFuc-yield 1"); yield return 1; Console.WriteLine("enumerableFuc-yield 2"); yield return 2; Console.WriteLine("enumerableFuc-yield 3"); yield return 3; }输出的结果:
4.MoveNext() 返回 false,结束迭代。