亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C# yield關鍵字詳解

2020-01-24 02:00:21
字體:
來源:轉載
供稿:網友

對于yield關鍵字我們首先看一下msdn的解釋:

如果你在語句中使用 yield 關鍵字,則意味著它在其中出現的方法、運算符或 get 訪問器是迭代器。 通過使用 yield 定義迭代器,可在實現自定義集合類型的 IEnumerable IEnumerator 模式時無需其他顯式類(保留枚舉狀態的類,有關示例,請參閱 IEnumerator<T>)。

yield是一個語法糖

看msdn 的解釋總是讓人感覺生硬難懂。其實yield關鍵字很好理解。首先我們對于性質有個了解。yield是一個語法糖。既然yield是在C#中的一個語法糖,那么就說明yield是對一種復雜行為的簡化,就是將一段代碼簡化為一種簡單的形式,方便我們程序員使用。

那么yield到底是對什么行為的簡化。我們首先來看一下yield的使用場景。

還是來看msdn上的例子。

復制代碼 代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
        
            foreach (int i in Power(2, 8, ""))
            {
                Console.Write("{0} ", i);
            }
            Console.ReadKey();
        }


        public static IEnumerable<int> Power(int number, int exponent, string s)
        {
            int result = 1;

            for (int i = 0; i < exponent; i++)
            {
                result = result * number;
                yield return result;
            }
            yield return 3;
            yield return 4;
            yield return 5;
        }

    }
}

這是msdn上yield的一種使用場景。

我們首先看一下下面的Power方法。該靜態方法返回一個IEnumerablel<int>類型的參數。按照我們平常的做法。應該對數據執行一定操作,然后return一個IEnumerablel<int>類型的參數。我們把Power方法改造如下:

復制代碼 代碼如下:

public static IEnumerable<int> Power(int number, int exponent, string s)
        {
            int result = 1;
            //接口不能實例化,我們這兒new一個實現了IEnumerable接口的List
            IEnumerable<int> example = new List<int>();
            for (int i = 0; i < exponent; i++)
            {
                result = result * number;
                (example as List<int>).Add(result);
            }
            return example;
        }

這是我們平常的思路。但是這樣做就有個問題。這兒要new一個List,或者任何實現了IEnumerable接口的類型。這樣也太麻煩了吧。要知道IEnumerable是一個常用的返回類型。每次使用都要new一個LIst,或者其他實現了該接口的類型。與其使用其他類型,不如我們自己定制一個實現了IEnumerable接口專門用來返回IEnumerable類型的類型。我們自己定制也很麻煩。所以微軟幫我們定制好了。這個類是什么,那就是yield關鍵字這個語法糖。

語法糖的實現(實現IEnumerable<T>接口的類)

我們來看一下yield的反編譯代碼。

復制代碼 代碼如下:

namespace ConsoleApplication2
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;

    internal class Program
    {
        private static void Main(string[] args)
        {
            IEnumerable<int> enumerable = Power(2, 8);
            Console.WriteLine("Begin to iterate the collection.");
            foreach (int num in Power(2, 8))
            {
                Console.Write("{0} ", num);
            }
            Console.ReadKey();
        }

        public static IEnumerable<int> Power(int number, int exponent)
        {
            <Power>d__0 d__ = new <Power>d__0(-2);
            d__.<>3__number = number;
            d__.<>3__exponent = exponent;
            return d__;
        }

        [CompilerGenerated]
        private sealed class <Power>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable
        {
            private int <>1__state;
            private int <>2__current;
            public int <>3__exponent;
            public int <>3__number;
            private int <>l__initialThreadId;
            public int <result>5__1;
            public int exponent;
            public int number;

            [DebuggerHidden]
            public <Power>d__0(int <>1__state)
            {
                this.<>1__state = <>1__state;
                this.<>l__initialThreadId = Environment.CurrentManagedThreadId;
            }

            private bool MoveNext()
            {
                switch (this.<>1__state)
                {
                    case 0:
                        this.<>1__state = -1;
                        this.<result>5__1 = 1;
                        Console.WriteLine("Begin to invoke GetItems() method");
                        this.<>2__current = 3;
                        this.<>1__state = 1;
                        return true;

                    case 1:
                        this.<>1__state = -1;
                        this.<>2__current = 4;
                        this.<>1__state = 2;
                        return true;

                    case 2:
                        this.<>1__state = -1;
                        this.<>2__current = 5;
                        this.<>1__state = 3;
                        return true;

                    case 3:
                        this.<>1__state = -1;
                        break;
                }
                return false;
            }

            [DebuggerHidden]
            IEnumerator<int> IEnumerable<int>.GetEnumerator()
            {
                Program.<Power>d__0 d__;
                if ((Environment.CurrentManagedThreadId == this.<>l__initialThreadId) && (this.<>1__state == -2))
                {
                    this.<>1__state = 0;
                    d__ = this;
                }
                else
                {
                    d__ = new Program.<Power>d__0(0);
                }
                d__.number = this.<>3__number;
                d__.exponent = this.<>3__exponent;
                return d__;
            }

            [DebuggerHidden]
            IEnumerator IEnumerable.GetEnumerator()
            {
                return this.System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator();
            }

            [DebuggerHidden]
            void IEnumerator.Reset()
            {
                throw new NotSupportedException();
            }

            void IDisposable.Dispose()
            {
            }

            int IEnumerator<int>.Current
            {
                [DebuggerHidden]
                get
                {
                    return this.<>2__current;
                }
            }

            object IEnumerator.Current
            {
                [DebuggerHidden]
                get
                {
                    return this.<>2__current;
                }
            }
        }
    }
}

反編譯代碼有三部分,其中程序的入口點   private static void Main(string[] args)    Power方法  public static IEnumerable<int> Power(int number, int exponent) 和我們自己寫的代碼一樣,但是反編譯代碼中還多了一個密封類

  private sealed class <Power>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable

現在情況已經明了了。yield這個語法糖實現了一個實現 IEnumerable<int>接口的類來返回我們需要到 IEnumerable<int>類型的數據。

我們再看一下反編譯后的Power方法

復制代碼 代碼如下:

public static IEnumerable<int> Power(int number, int exponent)
        {
            <Power>d__0 d__ = new <Power>d__0(-2);
            d__.<>3__number = number;
            d__.<>3__exponent = exponent;
            return d__;
        }

此時就確認,的確是使用了實現枚舉接口的類來返回我們需要的數據類型。

每次yield return <expression>;就會像該類的實例中添加 一條數據。當yield break;的時候停止添加。

至此yield的用法就很清楚了。當我們需要返回IEnumerable類型的時候,直接yield返回數據就可以了。也不用new一個list,或其他類型。所以yield是一個典型的語法糖。

yield使用中的特殊情況

我們看到編譯器將我們yield的數據添加到了一個集合中。Power方法在編譯器中實例化了一個實現枚舉接口的類型。但是我們在Power方法中寫一些方法,編譯器會如何處理

復制代碼 代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            //這兒調用了方法。
            var test = Power(2, 8, "");
            Console.WriteLine("Begin to iterate the collection.");
            //Display powers of 2 up to the exponent of 8:
            foreach (int i in Power(2, 8, ""))
            {
                Console.Write("{0} ", i);
            }
            Console.ReadKey();
        }
        public static IEnumerable<int> Power(int number, int exponent, string s)
        {
            int result = 1;
            if (string.IsNullOrEmpty(s))
            {
                //throw new Exception("這是一個異常");
                Console.WriteLine("Begin to invoke GetItems() method");
            }

            for (int i = 0; i < exponent; i++)
            {
                result = result * number;
                yield return result;
            }
            yield return 3;
            yield return 4;
            yield return 5;
        }
    }
}


按照我們的理解當我們 var test = Power(2, 8, "");的時候確實調用了Power方法。此時應該程序打印Console.WriteLine("Begin to invoke GetItems() method");然后繼續執行 Console.WriteLine("Begin to iterate the collection.");方法。所以打印順序應該是

 Begin to invoke GetItems() method

Begin to iterate the collection.

但是我們運行的時候卻發現

打印順序和我們想象的不同。此時還是去看反編譯代碼。

復制代碼 代碼如下:

namespace ConsoleApplication2
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;

    internal class Program
    {
        private static void Main(string[] args)
        {
            IEnumerable<int> enumerable = Power(2, 8, "");
            Console.WriteLine("Begin to iterate the collection.");
            foreach (int num in Power(2, 8, ""))
            {
                Console.Write("{0} ", num);
            }
            Console.ReadKey();
        }

        public static IEnumerable<int> Power(int number, int exponent, string s)
        {
            <Power>d__0 d__ = new <Power>d__0(-2);
            d__.<>3__number = number;
            d__.<>3__exponent = exponent;
            d__.<>3__s = s;
            return d__;
        }

        [CompilerGenerated]
        private sealed class <Power>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable
        {
            private int <>1__state;
            private int <>2__current;
            public int <>3__exponent;
            public int <>3__number;
            public string <>3__s;
            private int <>l__initialThreadId;
            public int <i>5__2;
            public int <result>5__1;
            public int exponent;
            public int number;
            public string s;

            [DebuggerHidden]
            public <Power>d__0(int <>1__state)
            {
                this.<>1__state = <>1__state;
                this.<>l__initialThreadId = Environment.CurrentManagedThreadId;
            }

            private bool MoveNext()
            {
                switch (this.<>1__state)
                {
                    case 0:
                        this.<>1__state = -1;
                        this.<result>5__1 = 1;
                        if (string.IsNullOrEmpty(this.s))
                        {
                            Console.WriteLine("Begin to invoke GetItems() method");
                        }
                        this.<i>5__2 = 0;
                        while (this.<i>5__2 < this.exponent)
                        {
                            this.<result>5__1 *= this.number;
                            this.<>2__current = this.<result>5__1;
                            this.<>1__state = 1;
                            return true;
                        Label_009D:
                            this.<>1__state = -1;
                            this.<i>5__2++;
                        }
                        this.<>2__current = 3;
                        this.<>1__state = 2;
                        return true;

                    case 1:
                        goto Label_009D;

                    case 2:
                        this.<>1__state = -1;
                        this.<>2__current = 4;
                        this.<>1__state = 3;
                        return true;

                    case 3:
                        this.<>1__state = -1;
                        this.<>2__current = 5;
                        this.<>1__state = 4;
                        return true;

                    case 4:
                        this.<>1__state = -1;
                        break;
                }
                return false;
            }

            [DebuggerHidden]
            IEnumerator<int> IEnumerable<int>.GetEnumerator()
            {
                Program.<Power>d__0 d__;
                if ((Environment.CurrentManagedThreadId == this.<>l__initialThreadId) && (this.<>1__state == -2))
                {
                    this.<>1__state = 0;
                    d__ = this;
                }
                else
                {
                    d__ = new Program.<Power>d__0(0);
                }
                d__.number = this.<>3__number;
                d__.exponent = this.<>3__exponent;
                d__.s = this.<>3__s;
                return d__;
            }

            [DebuggerHidden]
            IEnumerator IEnumerable.GetEnumerator()
            {
                return this.System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator();
            }

            [DebuggerHidden]
            void IEnumerator.Reset()
            {
                throw new NotSupportedException();
            }

            void IDisposable.Dispose()
            {
            }

            int IEnumerator<int>.Current
            {
                [DebuggerHidden]
                get
                {
                    return this.<>2__current;
                }
            }

            object IEnumerator.Current
            {
                [DebuggerHidden]
                get
                {
                    return this.<>2__current;
                }
            }
        }
    }
}

我們看到Power方法

復制代碼 代碼如下:

public static IEnumerable<int> Power(int number, int exponent, string s)
        {
            <Power>d__0 d__ = new <Power>d__0(-2);
            d__.<>3__number = number;
            d__.<>3__exponent = exponent;
            d__.<>3__s = s;
            return d__;
        }

還是還我們沒有加打印方法之前一樣。我們的打印方法并沒有出現在Power方法中,而是被封裝進了實現枚舉接口的類方法  private bool MoveNext()中。所以方法不會立即被執行,而是在我們使用數據的時候被執行。如果對此機制不了解,就容易出現另外一些意想不到的問題。例如在Power方法中添加一些驗證程序,如果不符合條件就拋出一個異常。這樣的異常檢查不會被執行。只有我們使用數據的時候才會執行。這樣就失去了檢查數據的意義。

具體的例子可以看Artech博主的文章

另外使用yield還有一些注意事項:

你不能在具有以下特點的方法中包含 yield return 或 yield break 語句:

匿名方法。 有關詳細信息,請參閱匿名方法(C# 編程指南)。

包含不安全的塊的方法。 有關詳細信息,請參閱unsafe(C# 參考)。

異常處理

不能將 yield return 語句置于 try-catch 塊中。 可將 yield return 語句置于 try-finally 語句的 try 塊中。

yield break 語句可以位于 try 塊或 catch 塊,但不能位于 finally 塊。

如果 foreach 主體(在迭代器方法之外)引發異常,則將執行迭代器方法中的 finally 塊。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩美女免费视频| 日韩欧美中文字幕在线播放| 久久不射热爱视频精品| 精品久久久久久国产91| 国模吧一区二区| 欧美成人精品三级在线观看| 国产精品黄页免费高清在线观看| 国产成人精品久久亚洲高清不卡| 日韩精品免费观看| 久久综合伊人77777尤物| 欧美国产日韩精品| 日韩一二三在线视频播| 国产一区二区美女视频| 97国产真实伦对白精彩视频8| 深夜福利国产精品| 成人欧美在线视频| 欧美乱妇40p| 欧美成人午夜激情在线| 亚洲国产小视频在线观看| 亚洲影视九九影院在线观看| 亚洲欧美日韩视频一区| 国产婷婷色综合av蜜臀av| 国产99久久精品一区二区 夜夜躁日日躁| 日韩在线观看免费网站| 九九视频直播综合网| 国产精品久久久久久av福利软件| 国产精品免费视频久久久| 久久九九免费视频| 欧美高跟鞋交xxxxxhd| 中文字幕欧美精品日韩中文字幕| 狠狠色狠狠色综合日日小说| 午夜精品久久久久久久99热浪潮| 欧美性猛交xxxx久久久| 久久久999国产| 色偷偷噜噜噜亚洲男人的天堂| 精品国产户外野外| 亚洲精品白浆高清久久久久久| 精品久久久精品| 欧美高清在线观看| 欧美一级淫片播放口| 亚洲乱码国产乱码精品精| 欧美成人黄色小视频| 伊人男人综合视频网| 国产精品三级在线| 亚洲xxx自由成熟| 亚洲国产成人久久| 日韩欧美亚洲一二三区| 国产亚洲人成网站在线观看| 国产91精品久| 日本久久久久久| 久久久电影免费观看完整版| 成人午夜在线视频一区| 91九色在线视频| 日韩亚洲精品电影| 国产一级揄自揄精品视频| 成人福利在线视频| 91在线视频九色| 国产精品草莓在线免费观看| 日韩精品在线播放| 日韩电影免费在线观看中文字幕| 九色精品免费永久在线| 亚洲一区二区久久久| 亚洲欧洲成视频免费观看| 精品视频久久久| 日本国产欧美一区二区三区| 一区二区国产精品视频| 2020欧美日韩在线视频| 久久av红桃一区二区小说| 日韩欧美第一页| 久久69精品久久久久久国产越南| 欧美激情精品久久久久久大尺度| www.午夜精品| 国产精品美女视频网站| 国产成人精品在线观看| 精品福利一区二区| 一区二区三欧美| 欧美亚洲第一区| 国产亚洲精品一区二区| 精品国产一区二区三区久久久狼| 九九九久久国产免费| 亚洲国产婷婷香蕉久久久久久| 久久五月天综合| 久久人人爽人人爽人人片av高请| 国产精品日日摸夜夜添夜夜av| 欧美日本高清一区| 欧美多人爱爱视频网站| 91精品国产自产在线观看永久| 欧美视频二区36p| 欧美日韩激情视频8区| 欧美成人中文字幕在线| 国产精品视频xxx| 日韩精品有码在线观看| 96sao精品视频在线观看| 久久久久www| 少妇av一区二区三区| 日韩精品视频免费| 色婷婷久久一区二区| 精品视频在线播放色网色视频| 国产ts人妖一区二区三区| 国产欧美精品日韩精品| www.久久草.com| 欧美精品www在线观看| 国产亚洲精品美女| 97精品视频在线| 久久精品国产精品亚洲| 日韩中文字幕在线视频| 日韩一二三在线视频播| 精品国产欧美一区二区五十路| 色中色综合影院手机版在线观看| 97久久精品人人澡人人爽缅北| 国产精品网站入口| 欧美大片va欧美在线播放| 欧美理论片在线观看| 国产一区二区精品丝袜| 成人h片在线播放免费网站| 91久久国产婷婷一区二区| 国产91精品久久久久| 久久精品国产亚洲精品| 欧美激情免费在线| 久久久99久久精品女同性| 国产精品美女主播在线观看纯欲| 国产精品www网站| 欧美一区亚洲一区| 国产高清在线不卡| 欧美成人激情视频| 欧美电影免费观看电视剧大全| 久久精品国产一区二区电影| 欧美日韩成人在线观看| 欧美日韩亚洲天堂| 亚洲精品视频播放| 91亚洲人电影| 色偷偷av一区二区三区| 91日本在线视频| 久久综合亚洲社区| 91精品国产综合久久香蕉的用户体验| 欧美国产欧美亚洲国产日韩mv天天看完整| 97香蕉久久夜色精品国产| 成人免费网站在线| 成人乱人伦精品视频在线观看| 超在线视频97| 日韩成人网免费视频| 亚洲成avwww人| 亚洲偷欧美偷国内偷| 国产精品露脸自拍| 久久精品成人动漫| 欧美老女人xx| 爽爽爽爽爽爽爽成人免费观看| 日日骚久久av| 亚洲午夜未满十八勿入免费观看全集| 国产精品永久免费视频| 欧美黑人巨大xxx极品| 欧美精品videosex极品1| 久久国产精品久久久| 高潮白浆女日韩av免费看| 国产成人亚洲综合青青| 亚洲色图狂野欧美| 国产精品久久久久久久久久久不卡| 欧美精品性视频| 成人www视频在线观看| 亚洲女性裸体视频| 97视频人免费观看| 中文精品99久久国产香蕉| 国产一区二区成人| 国产精品久久久久久网站|