查看原文
其他

如何在 C# 中使用 yield

DotNet 2021-09-23

The following article is from 码农读书 Author 码农读书

yield关键词是在 C# 2.0 中被引入的,我们都知道实现了 IEnumerable 接口的类都可以用于被 foreach 迭代,这是因为 IEnumerable 接口中提供了一个可迭代的 GetEnumerator() 方法,代码定义如下:

public interface IEnumerable  
{  
   IEnumerator GetEnumerator();  
}  

现在你也可以使用 yield 关键词来指定某些方法也是可以被迭代的,通常 C# 中有两种 yield 的语法格式:yield return <expression>yield break

为什么要使用 yield 关键词

yield关键词可以实现一种 状态迭代 而不需要提前创建好一个临时集合,换句话说,当你在迭代器中使用 yield return 时,在数据返回之前你不需要创建一个临时集合来存储数据,你可以利用 yield return 一次性返回集合中的每项数据,同时你也可以在方法和get访问器中使用带有迭代的 yield return 语句,值得注意的是,当每次执行 yield return 语句后,控制权都会转交给调用者。说了这么多,如果有点懵的话,我们来看一个例子,下面的代码展示了如何使用 yield 关键词来返回 Fibonacci 数字,这个方法接收一个int类型的参数。

        static IEnumerable<int> GenerateFibonacciNumbers(int n)  
        {  
            for (int i = 0, j = 0, k = 1; i < n; i++)  
            {  
                yield return j;  
                int temp = j + k;  
                j = k;  
                k = temp;  
            }  
        }  

上面的代码中 yield return j 在不退出 for 循环的情况下逐个返回斐波那契数,换句话说,这个迭代状态是被保留的,下面的代码展示了如何调用 GenerateFibonacciNumbers()

            foreach (int x in GenerateFibonacciNumbers(10))  
            {  
                Console.WriteLine(x); 
            }  

下面是仅供参考的完整代码。

    class Program  
    {  
        static void Main(string[] args)  
        {  
            foreach (int x in GenerateFibonacciNumbers(10))  
            {  
                Console.WriteLine(x);  
            }  
        }  
  
        static IEnumerable<int> GenerateFibonacciNumbers(int n)  
        {  
            for (int i = 0, j = 0, k = 1; i < n; i++)  
            {  
                yield return j;  
                int temp = j + k;  
                j = k;  
                k = temp;  
            }  
        }  
    }  


也许你注意到了,上面的代码并没有创建一个 list 或者 array 去存放那些输出到控制台的斐波那契额数。yield 关键词的另一个优点在于可以按需创建和返回你需要的数,下面的代码展示了 Get方法器 中仅返回 1-10 之间的偶数。

        public static IEnumerable<int> EvenNumbers  
        {  
            get  
            {  
                for (int i = 1; i <= 10; i++)  
                {  
                    if ((i % 2) == 0)  
                        yield return i;  
                }  
            }  
        }  

你也可以使用 yield break 来提前中断一个迭代链,如下代码所示:

        public IEnumerable<T> GetData<T>(IEnumerable<T> items)  
        {  
            if (null == items)  
                yield break;  
  
            foreach (T item in items)  
                yield return item;  
        }  

几点原则

当你在用 yield 时,请记住如下几点。

  • yield return 不能套在 try-catch 中,否则会报错。

  • yield break 不能放在 finally 中。
  • yield 方法的返回类型只能是 IEnumerable, IEnumerable<T>, IEnumerator,IEnumerator<T>
  • 在 yiled 的方法参数中不能使用 ref,out 标记。
  • 不能将 yield returnyield break 放在匿名方法中。
  • 不能将 yield returnyield break 放在 unsafe 方法中。

- EOF -

推荐阅读  点击标题可跳转
ASP.NET Core 限流控制:AspNetCoreRateLimitC# 开源一个新的雪花算法高并发下的服务器架构演变


看完本文有收获?请转发分享给更多人

推荐关注「DotNet」,提升.Net技能 

点赞和在看就是最大的支持❤️

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存