如何在 C# 中使用 yield?

dotNET全栈开发

共 6739字,需浏览 14分钟

 · 2021-04-19

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<intGenerateFibonacciNumbers(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<intGenerateFibonacciNumbers(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 方法中。

译文链接:https://www.infoworld.com/article/3122592/my-two-cents-on-the-yield-keyword-in-c.html







回复 【关闭】广
回复 【实战】获取20套实战源码
回复 【被删】
回复 【访客】访
回复 【小程序】学获取15套【入门+实战+赚钱】小程序源码
回复 【python】学微获取全套0基础Python知识手册
回复 【2019】获取2019 .NET 开发者峰会资料PPT
回复 【加群】加入dotnet微信交流群

人人影视字幕组凉了,这款美剧APP不能错过!


谷歌灵魂插件,98%的程序员都好评!



浏览 24
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报