程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 探秘C#中的yield關鍵字,

探秘C#中的yield關鍵字,

編輯:C#入門知識

探秘C#中的yield關鍵字,


在"C#中,什麼時候用yield return"中,我們了解到:使用yield return返回集合,不是一次性加載到內存中,而是客戶端每調用一次就返回一個集合元素,是一種"按需供給"。本篇來重溫yield return的用法,探秘yield背後的故事並自定義一個能達到yield return相同效果的類,最後體驗yield break的用法。

 

□ 回顧yield return的用法

以下代碼創建一個集合並遍歷集合。

   class Program
    {
        static Random r = new Random();
        static IEnumerable<int> GetList(int count)
        {
            List<int> list = new List<int>();
            for (int i = 0; i < count; i++)
            {
                list.Add(r.Next(10));
            }
            return list;
        }
        static void Main(string[] args)
        {
            foreach(int item in GetList(5))
                Console.WriteLine(item);
            Console.ReadKey();
        }
    }

 

使用yield return也能獲得同樣的結果。修改GetList方法為:

        static IEnumerable<int> GetList(int count)
        {
            for (int i = 0; i < count; i++)
            {
                yield return r.Next(10);
            }
        }
通過斷點調試發現:客戶端每顯示一個集合中的元素,都會到GetList方法去獲取集合元素。

 

□ 探密yield

使用yield return獲取集合,並遍歷。

    class Program
    {
        public static Random r = new Random();
        static IEnumerable<int> GetList(int count)
        {
            for (int i = 0; i < count; i++)
            {
                yield return r.Next(10);
            }
        }
        static void Main(string[] args)
        {
            foreach(int item in GetList(5))
                Console.WriteLine(item);
            Console.ReadKey();
        }
    }

生成項目,並用Reflector反編譯可執行文件。在.NET 1.0版本下查看GetList方法,發現該方法返回的是一個GetList類的實例。原來yield return是"語法糖",其本後是生成了一個GetList的實例。

 

那GetList實例是什麼呢?點擊Reflector中<GetList>鏈接查看。

○ 原來GetList類實現了IEnumerable和IEnumerator的泛型、非泛型接口
○ yield return返回的集合之所以能被迭代、遍歷,是因為GetList內部有迭代器
○ yield return之所以能實現"按需供給",是因為GetList內部有一個_state字段記錄這上次的狀態

 

接下來,就模擬GetList,我們自定義一個GetRandomNumbersClass類,使之能達到yield return相同的效果。

using System;
using System.Collections;
using System.Collections.Generic;
namespace ConsoleApplication2
{
    class Program
    {
        public static Random r = new Random();
        static IEnumerable<int> GetList(int count)
        {
            GetRandomNumbersClass ret = new GetRandomNumbersClass();
            ret.count = count;
            return ret;
        }
        static void Main(string[] args)
        {
            foreach(int item in GetList(5))
                Console.WriteLine(item);
            Console.ReadKey();
        }
    }
    class GetRandomNumbersClass : IEnumerable<int>, IEnumerator<int>
    {
        public int count;//集合元素的數量
        public int i; //當前指針
        private int current;//存儲當前值
        private int state;//保存遍歷的狀態
        #region 實現IEnumerator接口
        public int Current
        {
            get { return current; }
        }
        public bool MoveNext()
        {
            switch (state)
            {
                case 0: //即為初始默認值
                    i = 0;//把指針調向0
                    goto case 1;
                    break;
                case 1:
                    state = 1;//先設置原狀態
                    if (!(i < count))//如果指針大於等於當前集合元素數量
                    {
                        return false;
                    }
                    current = Program.r.Next(10);
                    state = 2; //再設置當前狀態
                    return true;
                    break;
                case 2: //再次遍歷如果state值為2
                    i++;//指針再移動一位
                    goto  case 1;
                    break;
                    
            }
            return false;
        }
        //被顯式調用的屬性
        object IEnumerator.Current
        {
            get { return Current; }
        }
        public void Reset()
        {
            throw new NotImplementedException();
        }
        public void Dispose()
        {
        }
        #endregion
        #region 實現IEnumerable的泛型和非泛型
        public IEnumerator<int> GetEnumerator()
        {
            return this;
        }
        //被顯式調用的屬性
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        #endregion
    }
}

關於GetRandomNumbersClass類:
○ count表示集合的長度,可以在客戶端賦值。當調用迭代器的MoveNext方法,需要把count和當前位置比較,以決定是否可以再向前移動。
○ 字段i相當於索引,指針每次移動一位,i需要自增1
○ current表示當前存儲的值,外部通過IEnumerator.Current屬性訪問

 

迭代器的MoveNext方法是關鍵:
○ state字段是整型,表示產生集合過程中的3種狀態
○ 當state為0的時候,說明是初始狀態,把索引位置調到0,並跳轉到state為1的部分
○ 當state為1的時候,首先把狀態設置為1,然後判斷索引的位置有沒有大於或等於集合的長度,接著產生集合元素,把state設置為2,並最終返回true
○ 當sate為2的時候,也就是迭代器向前移動一位,再次執行MonveNext方法的時候,跳轉到state為2的語句塊部分,把索引位置自增1,再跳轉到state為1的語句塊中,產生新的集合元素
○ 如此循環


□ yield break的用法  

假設在一個無限循環的環境中獲取一個int類型的集合,在客戶端通過某個條件來終止循環。

    class Program
    {
        static Random rand = new Random();
        static IEnumerable<int> GetList()
        {
            while (true)
            {
                yield return rand.Next(100);
            }
        }
        static void Main(string[] args)
        {
            foreach (int item in GetList())
            {
                if (item%10 == 0)
                {
                    break;
                }
                Console.WriteLine(item);
                
            }
            Console.ReadKey();
        }
    }    

以上,當集合元素可以被10整除的時候,就終止循環。終止循環的時機是在循環遍歷的時候。

 

如果用yield break,就可以在獲取集合的時候,當符合某種條件就終止獲取集合。

    class Program
    {
        static Random rand = new Random();
        static IEnumerable<int> GetList()
        {
            while (true)
            {
                int temp = rand.Next(100);
                if (temp%10 == 0)
                {
                    yield break;
                }
                yield return temp;
            }
        }
        static void Main(string[] args)
        {
            foreach (int item in GetList())
            {
                Console.WriteLine(item);             
            }
            Console.ReadKey();
        }
    }

 

總結:
○ yield return能返回一個"按需供給"的集合
○ yield return是"語法糖",其背後是一個實現了IEnuerable,IEnumerator泛型、非泛型接口的類,該類維護著一個狀態字段,以保證yield return產生的集合能"按需供給"
○ yield break配合yield return使用,當產生集合達到某種條件的時候使用yield break,以終止繼續創建集合

 

 


CCTV10-百科探秘

discovery.cctv.com/special/C18375/01/
這是專題網站

目前還沒有視頻提供
 

古道探秘是什活動?

  古道探秘活動是雪花啤酒浙江公司首創的以走訪歷史古道為具體形式的大型系列戶外活動,活動倡導“積極、進取、挑戰、創新”的生活方式,活動范圍覆蓋浙江全域,向鄰近省市輻射;分別由專業戶外機構進行組織和實施,並由浙江省主流報紙進行全程跟蹤報道。活動一經推出,社會反響非常強烈,浙江省內各大媒體如《錢江晚報》、《湖州晚報》、《溫州商報》、《紹興晚報》、《南湖晚報》還有浙江旅游網、浙江在線、錢報論壇、旅游論壇、戶外運動論壇、博客、個人空間等等紛紛進行報道或轉載,社會各界參與雪花啤酒古道探秘活動的熱情空前高漲。現在探秘線路一經發出,報名電話就應接不暇,參加的名額馬上就被預訂一空,一“票”難求。
  截止截止2011年2月10日,據不完全統計:
  百度搜索:古道探秘,找到相關網頁約662,000篇

  活動背景:
  浙江具有豐富的旅游文化資源,古道古跡、古村古鎮資源眾多。如今那些已經滄桑千年的古道,多已荒蕪在深山老林之中,雜草叢生,人跡罕至。不過這些曾經繁華的古道卻寄存著很多珍貴的歷史記憶,如古詩古畫、民風民俗、古村落、古建築等等,重走古道不僅僅是一次遠足或者跋涉,某種程度上更是一種對積澱千年的歷史、文化的近距離觸摸和感悟。
  背起行囊
  讓灑滿陽光的山林濾掉都市的喧囂
  遠足者的腳步叩響千年古道
  在青山碧水間
  在古道老樹旁
  讓我們訪古探今
  觸摸中國文化幾千年的積澱
  徽杭古道、仙霞古道、仙缙古道、括蒼古道……
  身處浙江,你是否曾體味過悠悠的古道之旅?

  活動規劃:
  第一階段:持續2010年全年
  第二階段:2011年全年
  出行時間:逢周六出發,每次歷時兩天(逢法定假日可能會延長時間);

  參與辦法:
  1、登陸浙江在線·我愛雪花網 了解最新探秘信息、報名辦法、探秘成果。
  2、《錢江晚報》、《湖州晚報》、《溫州商報》、《紹興晚報》、《南湖晚報》等均有報道。

  活動要求:
  A、年齡18-50周歲
  B、身體健康,無重大心腦血管疾病(出發前需驗證個人體檢證明或報告)
  C、需有一定的戶外徒步經驗,具備負重5公裡以上連續徒步能力。

  探秘體驗
  2010年1月23-24日
  成功穿越曾被譽為“海上絲綢之路”、“兵家必爭”、“詩文璀璨”的仙霞古道;
  仙霞古道,在崇山峻嶺中蜿蜒,一路林木森森、篁竹蔽天,古道石縫中冒出青草,有濃濃的蒼涼感,道道險關扼守著這條從唐朝到近代浙閩間唯一的商旅要道,其中仙霞關有“東南鑰匙、八閩咽喉”之稱。仙霞山脈深處的二十八都古鎮,存在著143種姓氏、13種方言;徐霞客、白居易、王安石、海瑞、徐渭,黃公度、陸游、楊萬裡、朱熹等等在仙霞古道上留下了350多篇文采飛揚的詩篇,讓人目眩神迷又如獲至寶。
  漫步青苔石階,尋訪那段塵囂遠去的歷史,帶著對古道的一個又一個疑問,在瀝瀝冬雨中40多名戶外愛好者共同上路,激情穿越曾被譽為“海上絲綢之路”、“兵家必爭之地”、“詩文璀璨之道”的仙霞古道。

  2010年3月6-7日
  體驗了有著“人雲蜀道苦難行,我到雲間兩腳輕”之險的仙缙古道;
  仙霞之後,下一站去哪裡,我們通過在錢報及錢報論壇上發布多條線路進行同台pk,“下一站去哪裡?您說了算!”,最後仙缙古道勝出,徽杭古道緊隨其後。
  仙缙古道兩側大山夾峙,山勢險峻,山道蜿蜒,被驢友們稱為“浙江西南第一嶺”,是浙江省十大徒步行走線路之一。古道途中有俞坑常綠闊葉林自然保護區,資源豐富:有如蓮的奇瀑、難尋的怪石、如夢如幻的瑤池仙境、明可見底的清泉。還有至今未解的千古之謎“蝌蚪文”......余下全文>>
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved