最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C# yield關(guān)鍵字詳解

 更新時間:2015年04月10日 11:12:50   投稿:junjie  
這篇文章主要介紹了C# yield關(guān)鍵字詳解,本文講解了yield是一個語法糖、語法糖的實現(xiàn)(實現(xiàn)IEnumerable<T>接口的類)、yield使用中的特殊情況等內(nèi)容,需要的朋友可以參考下

對于yield關(guān)鍵字我們首先看一下msdn的解釋:

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

yield是一個語法糖

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

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

還是來看msdn上的例子。

復(fù)制代碼 代碼如下:

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方法。該靜態(tài)方法返回一個IEnumerablel<int>類型的參數(shù)。按照我們平常的做法。應(yīng)該對數(shù)據(jù)執(zhí)行一定操作,然后return一個IEnumerablel<int>類型的參數(shù)。我們把Power方法改造如下:

復(fù)制代碼 代碼如下:

public static IEnumerable<int> Power(int number, int exponent, string s)
        {
            int result = 1;
            //接口不能實例化,我們這兒new一個實現(xiàn)了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,或者任何實現(xiàn)了IEnumerable接口的類型。這樣也太麻煩了吧。要知道IEnumerable是一個常用的返回類型。每次使用都要new一個LIst,或者其他實現(xiàn)了該接口的類型。與其使用其他類型,不如我們自己定制一個實現(xiàn)了IEnumerable接口專門用來返回IEnumerable類型的類型。我們自己定制也很麻煩。所以微軟幫我們定制好了。這個類是什么,那就是yield關(guān)鍵字這個語法糖。

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

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

復(fù)制代碼 代碼如下:

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

現(xiàn)在情況已經(jīng)明了了。yield這個語法糖實現(xiàn)了一個實現(xiàn) IEnumerable<int>接口的類來返回我們需要到 IEnumerable<int>類型的數(shù)據(jù)。

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

復(fù)制代碼 代碼如下:

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__;
        }

此時就確認(rèn),的確是使用了實現(xiàn)枚舉接口的類來返回我們需要的數(shù)據(jù)類型。

每次yield return <expression>;就會像該類的實例中添加 一條數(shù)據(jù)。當(dāng)yield break;的時候停止添加。

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

yield使用中的特殊情況

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

復(fù)制代碼 代碼如下:

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)
        {
            //這兒調(diào)用了方法。
            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;
        }
    }
}


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

 Begin to invoke GetItems() method

Begin to iterate the collection.

但是我們運行的時候卻發(fā)現(xiàn)

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

復(fù)制代碼 代碼如下:

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方法

復(fù)制代碼 代碼如下:

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__;
        }

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

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

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

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

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

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

異常處理

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

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

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

相關(guān)文章

  • 詳解C#中普通緩存的使用

    詳解C#中普通緩存的使用

    緩存的概念及優(yōu)缺點在這里就不多做介紹,當(dāng)然緩存包含多種有普通緩存、客戶端緩存、DNS緩存、反向代理緩存以及分布式緩存等等。今天主要聊一聊C#通過編碼來實現(xiàn)普通的緩存、話不多說直接上代碼。
    2021-05-05
  • Unity實現(xiàn)OCR文字識別功能

    Unity實現(xiàn)OCR文字識別功能

    這篇文章主要介紹了通過Unity接入百度AI接口,實現(xiàn)OCR文字識別功能,文中的實現(xiàn)步驟講解詳細(xì),對我們學(xué)習(xí)或工作有一定的參考價值,需要的可以了解一下
    2022-01-01
  • C#中時間類的使用方法詳解

    C#中時間類的使用方法詳解

    這篇文章主要介紹C#中的時間類,文中主要介紹了DateTime類,TimeSpan類,DateTimeOffset類及靜態(tài)類的封裝,通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • C#實現(xiàn)判斷當(dāng)前操作用戶管理角色的方法

    C#實現(xiàn)判斷當(dāng)前操作用戶管理角色的方法

    這篇文章主要介紹了C#實現(xiàn)判斷當(dāng)前操作用戶管理角色的方法,涉及C#針對系統(tǒng)用戶判斷的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-08-08
  • C#泛型委托的用法實例分析

    C#泛型委托的用法實例分析

    這篇文章主要介紹了C#泛型委托的用法,以實例形式較為詳細(xì)的分析了C#委托的功能與相關(guān)使用技巧,需要的朋友可以參考下
    2015-05-05
  • C#之IP地址和整數(shù)互轉(zhuǎn)的小例子

    C#之IP地址和整數(shù)互轉(zhuǎn)的小例子

    C#之IP地址和整數(shù)互轉(zhuǎn)的小例子,需要的朋友可以參考一下
    2013-03-03
  • C#實現(xiàn)隨機(jī)洗牌的方法

    C#實現(xiàn)隨機(jī)洗牌的方法

    這篇文章主要介紹了C#實現(xiàn)隨機(jī)洗牌的方法,涉及隨機(jī)數(shù)操作技巧,非常具有實用價值,需要的朋友可以參考下
    2015-02-02
  • C#?生成隨機(jī)數(shù)的方法示例

    C#?生成隨機(jī)數(shù)的方法示例

    本文介紹了C#中的Random類,用于生成隨機(jī)數(shù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • 淺談C# 非模式窗體show()和模式窗體showdialog()的區(qū)別

    淺談C# 非模式窗體show()和模式窗體showdialog()的區(qū)別

    下面小編就為大家?guī)硪黄獪\談C# 非模式窗體show()和模式窗體showdialog()的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-07-07
  • C#Url操作類封裝、仿Node.Js中的Url模塊實例

    C#Url操作類封裝、仿Node.Js中的Url模塊實例

    這篇文章主要介紹了C#Url操作類封裝、仿Node.Js中的Url模塊,實例分析了C#Url操作類封裝的技巧,非常具有實用價值,需要的朋友可以參考下。
    2016-10-10

最新評論

凉城县| 曲靖市| 鸡东县| 轮台县| 怀宁县| 海南省| 栾川县| 元阳县| 大埔区| 富源县| 郴州市| 台北县| 湄潭县| 壤塘县| 拜泉县| 和顺县| 江孜县| 镇沅| 石门县| 抚远县| 鄂尔多斯市| 佛山市| 星子县| 宣武区| 大洼县| 渭南市| 承德市| 固阳县| 南通市| 道孚县| 张家口市| 汪清县| 建始县| 理塘县| 册亨县| 屏东市| 闵行区| 手游| 辽宁省| 沽源县| 泸定县|