【C#復(fù)習(xí)知識(shí)點(diǎn)4】 委托、事件、接口、轉(zhuǎn)換、泛型、枚舉器和迭代器

——委托

可以理解為:委托是一個(gè)包含有序方法列表的對(duì)象,這些方法擁有相同類型的參數(shù)列表和返回值。
委托既可以卸載類外,也可以寫在類內(nèi)。
委托可以被繼承
委托既可以添加普通方法,也可以添加靜態(tài)方法。

    delegate string Delegate1(string str);        //聲明在類的外部
    class Base
    {
        public delegate int Delegate2(int val);   //聲明在類的內(nèi)部

        public void Fun()
        {
            Delegate1 de1 = new Delegate1(Fun3);  //創(chuàng)建類外部的委托的變量
            Console.WriteLine(de1("Delagate1"));

            Delegate2 de2 = new Delegate2(Fun1);  //創(chuàng)建類內(nèi)部的委托的變量
            de2 += Fun2;                          //添加靜態(tài)方法
            Console.WriteLine(de2(10));           //打印15,因?yàn)槲蟹祷刂禃?huì)返回最后一個(gè)方法的返回值
        }

        public int Fun1(int val)
        {
            return val * 2;
        }
        static int Fun2(int val)
        {
            return val + 5;
        }
        string Fun3(string str)
        {
            return str;
        }
    }
    class Child : Base
    {
        public void Method()
        {
            Delegate2 de = new Delegate2(Method1);   //使用基類內(nèi)部創(chuàng)建的委托
        }
        public int Method1(int val)
        {
            return val + 10;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Base b = new Base();
            b.Fun();
            Console.ReadLine();
        }
    }

如果委托使用引用參數(shù),那么這個(gè)參數(shù)在委托中第一個(gè)方法使用完后,得到的數(shù)值再傳入下一個(gè)方法。

匿名方法

所謂匿名方法,就是沒(méi)有名字的方法。
當(dāng)某些方法,只需要在委托中使用一次,其它地方不會(huì)調(diào)用這個(gè)方法,那么可以不聲明這個(gè)方法,在委托使用時(shí)以匿名方法添加上就ok。匿名函數(shù)不需要寫返回值。
比如:

    class Base
    {
        public delegate int MyDel(int val);        //委托

        public void Fun()
        {
            MyDel myDel1 = delegate (int val) { return val * 2; };//委托初始化時(shí)使用匿名方法
            myDel1 += delegate (int val) { return val + 5; };//添加方法時(shí)使用匿名放啊
        }
    }
Lambda表達(dá)式

Lambda表達(dá)式是就是用于進(jìn)一步簡(jiǎn)化匿名方法的(Lambda是在匿名方法之后才有的,如果先有Lambda,那么可能就不會(huì)有匿名方法了)。因此,所有可以用匿名函數(shù)的地方都可以使用Lambda表達(dá)式。下面的例子展示Lambda的用法。

    class Base
    {
        public delegate int MyDel1(int x, int y);//兩個(gè)參數(shù)的委托
        public delegate int MyDel2(int val);//一個(gè)參數(shù)的委托
        public delegate void MyDel3();//沒(méi)有參數(shù),沒(méi)有返回值的委托

        public void Fun()
        {
            MyDel1 myDel0 = delegate (int x,int y) { return x + y; };//匿名方法

            MyDel1 mydel1 = (int x, int y) => { return x + y; };//有兩個(gè)參數(shù)的Lambda表達(dá)式
            MyDel2 myDel2 = (val) => { return val * 2; };//如果只有一個(gè)參數(shù),那么可以不寫參數(shù)的類型
            MyDel2 myDel3 = val => { return val * 2; };//甚至括號(hào)都可以省略
            MyDel2 myDel4 = val => val * 2;//如果出了返回一個(gè)值,沒(méi)有其他語(yǔ)句,可以去掉大括號(hào)和return。
            MyDel3 myDel5 = () => { };//委托不需要返回值,也不需要參數(shù),如果沒(méi)有要執(zhí)行的方法體,可以簡(jiǎn)化到這樣
        }
    }

——事件

事件其實(shí)就是使用委托,只不過(guò)事件是專門用于某種特殊用途的委托。也就是發(fā)布者/訂閱者訂閱者模式。
發(fā)布者定義一系列的程序,訂閱者在發(fā)布者中注冊(cè)(也就是往發(fā)布者的委托中加入方法),以便在發(fā)布者發(fā)生事件時(shí)通知訂閱者(調(diào)用事件委托)。
事件對(duì)委托做了一些限制,
1、事件將內(nèi)部委托私有化,你無(wú)法在其他類中訪問(wèn)委托
2、事件的操作非常少,只有添加,移除,調(diào)用。
3、事件觸發(fā)時(shí),讓內(nèi)部委托依次調(diào)用方法列表中的方法。
4、事件是直接調(diào)用使用的,不可以實(shí)例化對(duì)象。
事件和委托其實(shí)就是下面這種結(jié)構(gòu)



一個(gè)普通的事件的使用:

    class Base
    {
        public delegate void Del();//定義事件用到的委托
        public event Del Eve;      //定義事件

        public void Fun()
        {
            Eve();                //調(diào)用事件
        }
    }
    class Other
    {
        Base b = new Base();
        public void Method()
        {
            b.Eve += Fun1;        //在事件中注冊(cè)
        }
        public void Fun1()
        {
            Console.WriteLine("this is Fun1");
        }
    }

——接口

什么時(shí)候是必須用到接口,而單純靠繼承是無(wú)法完成的呢?
比如下面的代碼,我們無(wú)法讓PrintInfo的參數(shù)可以接收任意類。

    class Ca
    {
        public void Fun()
        {
            Console.WriteLine("this is ca");
        }
    }
    class Cb
    {
        public void Fun()
        {
            Console.WriteLine("this is cb");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Ca ca = new Ca();
            Cb cb = new Cb();
            PrintInfo(ca);//打印 tihs is ca
            PrintInfo(cb);//錯(cuò)誤
            Console.ReadLine();
        }
        static void PrintInfo(Ca ca)
        {
            ca.Fun();
        }
    }

這個(gè)時(shí)候我們就可以使用接口,讓兩個(gè)類都實(shí)現(xiàn)這個(gè)接口,而PrintInfo函數(shù)的參數(shù)就是這個(gè)接口類型,這時(shí),由于兩個(gè)類都實(shí)現(xiàn)了IFun接口,所以它們都可以作為參數(shù)傳遞進(jìn)去

    interface IFun
    {
        void Fun();
    }
    class Ca : IFun
    {
        public void Fun()
        {
            Console.WriteLine("this is ca");
        }
    }
    class Cb : IFun
    {
        public void Fun()
        {
            Console.WriteLine("this is cb");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Ca ca = new Ca();
            Cb cb = new Cb();
            PrintInfo(ca);//打印this is ca
            PrintInfo(cb);//打印this is cb
            Console.ReadLine();
        }
        static void PrintInfo(IFun c)
        {
            c.Fun();
        }
    }
關(guān)于Array.Sort();方法

它其實(shí)不是可以排序int類型,而是可以排序繼承自IComparable接口的類型,在這個(gè)接口中包含唯一一個(gè)方法CompareTo(),這個(gè)方法規(guī)定,在調(diào)用它時(shí),需要返回一下幾個(gè)值:
負(fù)數(shù)值:當(dāng)前對(duì)象小于用于比較的參數(shù)對(duì)象
正數(shù)值:當(dāng)前對(duì)象大于用于比較的參數(shù)對(duì)象
0:當(dāng)前對(duì)象等與用于比較的參數(shù)對(duì)象
因?yàn)閕nt實(shí)現(xiàn)了IComparable接口的CompareTo()函數(shù),所以int類型可以排序,而Ca沒(méi)有實(shí)現(xiàn)這個(gè)接口,所以不能排序

    class Ca
    {
        public int value = 0;
    }

    class Program
    {
        static void Main(string[] args)
        {
            //排序一個(gè)int類型數(shù)組
            int[] arrs = new int[] { 5, 1, 3, 2, 4 };
            Array.Sort(arrs);
            foreach (var item in arrs)
            {
                Console.Write(item + " ");
            }

            //排序Ca類型數(shù)組
            Ca[] cas = new Ca[5];
            for (int i = 0; i < cas.Length; i++)
            {
                cas[i] = new Ca();
                cas[i].value = i + 1;
            }
            Array.Sort(cas);//這段可以正常寫,但是運(yùn)行會(huì)報(bào)錯(cuò)
            foreach (var item in cas)
            {
                Console.Write(item.value + " ");
            }
            Console.ReadLine();
        }
    }

所以需要讓Ca類實(shí)現(xiàn)IComparable接口,就可以排序了。

    class Ca : IComparable
    {
        public int value = 0;

        public int CompareTo(object obj)
        {
            Ca ca = (Ca)obj;
            if (value < ca.value)
            {
                return -1;
            }
            if (value > ca.value)
            {
                return 1;
            }
            return 0;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //排序Ca類型數(shù)組
            Ca[] cas = new Ca[5];
            for (int i = 0; i < cas.Length; i++)
            {
                cas[i] = new Ca();
                cas[i].value = i + 1;
            }
            Array.Sort(cas);//打印1 2 3 4 5
            foreach (var item in cas)
            {
                Console.Write(item.value + " ");
            }
            Console.ReadLine();
        }
    }
接口的成員

接口的成員只能是非靜態(tài)的函數(shù)成員,如方法,屬性,索引器,事件。

接口的實(shí)現(xiàn)

類和結(jié)構(gòu)體都可以實(shí)現(xiàn)接口

接口是引用類型

接口是引用類型,它雖然不可以實(shí)例化,但是可以用接口聲明引用,實(shí)現(xiàn)類去實(shí)例,就像父類引用,子類實(shí)例一樣,代碼如下:

    interface IFun
    {
        void Fun();
    }
    class Ca : IFun
    {
        public void Fun()
        {
            Console.WriteLine("this is fun");
        }
    }
    class Cb : Ca
    {

    }

    class Program
    {
        static void Main(string[] args)
        {
            Cb cb = new Cb();//子類對(duì)象
            cb.Fun();
            Ca ca = cb;//父類引用,子類實(shí)例
            ca.Fun();
            IFun ifun = ca;//接口引用,實(shí)現(xiàn)類實(shí)例
            ifun.Fun();

            Console.ReadLine();
        }
    }

在堆中的形式如下:


接口使用 as 運(yùn)算符

如果類沒(méi)有實(shí)現(xiàn)接口而去強(qiáng)轉(zhuǎn)為接口,那么會(huì)報(bào)錯(cuò),這時(shí),可以使用 as 運(yùn)算符強(qiáng)轉(zhuǎn),它可以讓無(wú)法發(fā)生的強(qiáng)轉(zhuǎn)返回null,而不是報(bào)錯(cuò),代碼如下:

    interface IFun
    {
        void Fun();
    }
    class Ca
    {
        public void Fun()
        {
            Console.WriteLine("this is fun");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Ca ca = new Ca();
            IFun ifun = ca;//報(bào)錯(cuò),因?yàn)镃a類沒(méi)有實(shí)現(xiàn)該接口
            IFun ifun = ca as IFun;//返回null而不是異常
            ifun.Fun();

            Console.ReadLine();
        }
    }
多個(gè)接口的函數(shù)成員簽名相同

如果一個(gè)類實(shí)現(xiàn)多個(gè)接口,并且多個(gè)接口定義的函數(shù)成員簽名相同,那么類可以實(shí)現(xiàn)單個(gè)函數(shù)滿足所有接口

   interface IFun1//接口1
    {
        string Fun(string s);
    }
    interface IFun2//接口2
    {
        string Fun(string s);
    }
    class Ca : IFun1,IFun2//實(shí)現(xiàn)接口1和接口2
    {
        public string Fun(string s)//實(shí)現(xiàn)一個(gè)函數(shù)滿足兩個(gè)接口
        {
            return s;
        }
    }
顯示實(shí)現(xiàn)接口成員

如果類繼承了兩個(gè)函數(shù)成員簽名一樣的接口,但是這兩個(gè)接口的函數(shù)成員實(shí)現(xiàn)不一樣的功能,那么需要分別實(shí)現(xiàn),可以使用顯示實(shí)現(xiàn)接口成員的方式,但是要注意,顯示實(shí)現(xiàn)接口成員只能私有,不能添加訪問(wèn)修飾符,并且調(diào)用也只能通過(guò)接口引用才可以調(diào)用,如下例子:

    interface IFun1//接口1
    {
        string Fun(string s);
    }
    interface IFun2//接口2
    {
        string Fun(string s);
    }
    class Ca : IFun1, IFun2//實(shí)現(xiàn)接口1和接口2
    {
        string IFun1.Fun(string s)
        {
            return "this is IFun1";
        }
        string IFun2.Fun(string s)
        {
            return "this is IFun2";
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IFun1 fun1 = new Ca();
            fun1.Fun("Fun1");//只能通過(guò)接口引用調(diào)用
            IFun2 fun2 = new Ca();
            fun2.Fun("Fun2");//只能通過(guò)接口引用調(diào)用

            Console.ReadLine();
        }
    }
接口的繼承
    interface IFun
    {
        void Fun();
    }
    class Ca//沒(méi)有繼承接口,但是有滿足接口的函數(shù)
    {
        public void Fun()
        {
            Console.WriteLine("this is fun");
        }
    }
    class Cb : Ca, IFun//繼承Ca,又繼承接口,間接使用Ca的Fun函數(shù)實(shí)現(xiàn)接口
    {
    }
    class Cc : Cb//繼承Cb
    {
    }

    class Program
    {
        static void Main(string[] args)
        {
            IFun ifun = new Cc();//使用Cc實(shí)例接口的引用
            ifun.Fun();
            Console.ReadLine();
        }
    }
接口可以繼承其他接口

直接看例子就能明白

    interface IFun1//接口1
    {
        string Fun(string s);
    }
    interface IFun2//接口2
    {
        string Fun(string s);
    }
    interface IFun : IFun1, IFun2
    {

    }
    class Ca : IFun//實(shí)現(xiàn)接口1和接口2
    {
        string IFun1.Fun(string s)
        {
            return "this is IFun1";
        }
        string IFun2.Fun(string s)
        {
            return "this is IFun2";
        }
    }

——轉(zhuǎn)換

checked和unchecked

checked和unchecked可以用來(lái)檢測(cè)溢出。
如果用于表達(dá)式,那么溢出時(shí),checked會(huì)拋出異常,unchecked會(huì)繼續(xù)執(zhí)行。

            int i = 100000;
            byte b = unchecked((byte)i);//打印b
            byte c = checked((byte)i);//拋出異常

也可以用作語(yǔ)句,如果用于語(yǔ)句,效果也是一樣的

            int i = 100000;
            checked
            {
                byte b = (byte)i;//拋出異常
            }
            unchecked
            {
                byte b = (byte)i;//繼續(xù)執(zhí)行
            }
浮點(diǎn)型轉(zhuǎn)換為整形

浮點(diǎn)型會(huì)舍去小數(shù)部分

double轉(zhuǎn)float

flaot占32位,double占64位,double 類型的值會(huì)舍入到最接近float類型的值。之后,如果值太小導(dǎo)致無(wú)法轉(zhuǎn)為float表示,那么值會(huì)被設(shè)置為正或負(fù)0.。如果值太大導(dǎo)致無(wú)法轉(zhuǎn)為float表示,那么值會(huì)被設(shè)置為無(wú)窮大或負(fù)無(wú)窮大。

關(guān)于引用類型的轉(zhuǎn)換

引用類型的轉(zhuǎn)換,其實(shí)是改變引用指向堆中的內(nèi)存。



顯示的引用類型轉(zhuǎn)換

之前說(shuō)過(guò),可以用父類聲明,子類構(gòu)造,但不可以子類聲明,父類構(gòu)造。之前解釋是會(huì)報(bào)錯(cuò),其實(shí)是拋出InvalidCastException異常,不會(huì)導(dǎo)致編譯錯(cuò)誤,需要特別注意。有兩種情況是可以子類聲明,父類構(gòu)造的
1、父類對(duì)象為空

    class A
    {
    }
    class B : A
    {
    }
    class Program
    {
        static void Main(string[] args)
        {
            A a = null;
            B b = (B)a;

            Console.ReadLine();
        }
    }

2、父類已經(jīng)是子類對(duì)象的引用

    class A
    {
    }
    class B : A
    {
    }
    class Program
    {
        static void Main(string[] args)
        {
            B b = new B();
            A a = b;
            B b2 = (B)a;

            Console.ReadLine();
        }
    }
裝箱

值類型默認(rèn)在堆上不包括它們的對(duì)象組件,然而,如果需要對(duì)象組件,我們可以使用裝箱。裝箱是一種隱式轉(zhuǎn)換,他接受值類型的值,根據(jù)這個(gè)值在堆上的創(chuàng)建一個(gè)完整的引用類型對(duì)象,并返回對(duì)象引用。也就是說(shuō),如果想把值類型轉(zhuǎn)為引用類型,可以通過(guò)裝箱。



如上面的例子,裝箱一個(gè)值類型。
上述例子存在一個(gè)知識(shí)點(diǎn),裝箱并不是在被裝箱的項(xiàng)上發(fā)生了操作,而是對(duì)值的副本進(jìn)行操作,裝箱之后會(huì)有原值和引用類型副本兩個(gè),都可以獨(dú)立操作。

拆箱

拆箱是將引用類型轉(zhuǎn)換為值類型顯示轉(zhuǎn)換,在拆箱時(shí),系統(tǒng)會(huì)進(jìn)行以下操作:
檢測(cè)要拆箱的對(duì)象實(shí)際的裝箱值。
把對(duì)象的值復(fù)制到變量里。
因此,拆箱后的變量和拆箱前的引用對(duì)象也都是獨(dú)立的。如果拆箱為一個(gè)非它的原始類型,會(huì)拋出InvalidCastException異常。

自定義轉(zhuǎn)換

之前介紹過(guò)自定義轉(zhuǎn)換,這里再說(shuō)幾點(diǎn)約束:
1、只能為類或結(jié)構(gòu)體定義自定義轉(zhuǎn)換,不能重新定義標(biāo)準(zhǔn)的隱式或顯示轉(zhuǎn)換
2、只能定義不同類型的轉(zhuǎn)換,不能是繼承關(guān)系。

is運(yùn)算符和as運(yùn)算符

is運(yùn)算符可以在轉(zhuǎn)換之前判斷是否可以轉(zhuǎn)換,返回true或false。

    class A
    {
    }
    class B : A
    {
    }
    class Program
    {
        static void Main(string[] args)
        {
            B b = new B();
            A a = null;
            if (a is B)//判斷是否可以轉(zhuǎn)換
            {
                a = b;
            }

            Console.ReadLine();
        }
    }

as運(yùn)算符進(jìn)行強(qiáng)制轉(zhuǎn)換,即使無(wú)法強(qiáng)制轉(zhuǎn)換也不會(huì)拋出異常,只會(huì)返回null。

——泛型

泛型的約束

使用where關(guān)鍵字
where T : struct 那么T只能是指類型
where T : class 那么T只能是引用類型(比如類,數(shù)組,委托,接口)
where T : 類型 那么T只能是這個(gè)類,或者是派生這類類
where T : 接口名 那么T只能是這個(gè)接口,或者是實(shí)現(xiàn)這個(gè)接口的類型
where T : class,new() 那么T必須包含公共的無(wú)參的構(gòu)造函數(shù),不然就會(huì)報(bào)錯(cuò)

——枚舉器與迭代器

對(duì)于數(shù)組可以使用forea遍歷,是因?yàn)閿?shù)組是一個(gè)可枚舉類型,可枚舉類型通過(guò)枚舉器訪問(wèn)每一個(gè)項(xiàng)。
IEnumerator(枚舉器接口)

枚舉器必須實(shí)現(xiàn)該接口,該接口包括3個(gè)重要的函數(shù)成員:
1、Current:它是一個(gè)屬性,是只讀的,用來(lái)返回當(dāng)前索引的項(xiàng),返回值是一個(gè)object,所以可以返回所有類型。
2、MoveNext:它是一個(gè)方法,用來(lái)把當(dāng)前索引移到下一個(gè)索引位置。返回一個(gè)bool值。
3、Reset:它是一個(gè)方法,用來(lái)把位置重置為原始狀態(tài)的方法。


IEnumerable(可枚舉類型)

可枚舉類型接口有一個(gè)函數(shù),就是GetEnumerator(),它返回一個(gè)IEnumerator,也即是枚舉器,foreach其實(shí)可以理解給我就是調(diào)用可枚舉類型中的GetEnumerator()獲取枚舉器,然后通過(guò)這個(gè)枚舉器調(diào)用MoveNext和Current來(lái)遍歷所有項(xiàng)。



下面演示一個(gè)簡(jiǎn)單的的枚舉器和可枚舉類型:

    //枚舉器
    class MyColor : IEnumerator
    {
        string[] color;
        int index = -1;

        public MyColor(string[] color)
        {
            this.color = new string[color.Length];
            for (int i = 0; i < color.Length; i++)
                this.color[i] = color[i];  
        }
        public object Current
        {
            get
            {
                if (index == -1)
                    throw new InvalidOperationException();
                else if (index > color.Length - 1)
                    throw new InvalidOperationException();
                return color[index];
            }
        }

        public bool MoveNext()
        {
            if (index < color.Length - 1)
            {
                index++;
                return true;
            }
            return false;
        }

        public void Reset()
        {
            index = -1;
        }
    }
    //Spectrum類定義為可枚舉類型
    class Spectrum : IEnumerable
    {
        string[] color = { "White", "Red", "Green", "Pink" };
        //使用MyColor枚舉器枚舉
        public IEnumerator GetEnumerator()
        {
            return new MyColor(color);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Spectrum spe = new Spectrum();
            foreach (var item in spe)//foreach遍歷
            {
                Console.WriteLine(item);
            }

            Console.ReadLine();
        }
    }

上述代碼Spectrum類為可枚舉類型,它使用MyColor枚舉器進(jìn)行枚舉,所以它可以被foreach遍歷。
其實(shí)主函數(shù)的foreach就相當(dāng)于如下代碼:

    class Program
    {
        static void Main(string[] args)
        {
            Spectrum spe = new Spectrum();

            IEnumerator enumerator = spe.GetEnumerator();//獲取枚舉器

            while (enumerator.MoveNext())//索引寫一個(gè)
            {
                object obj = enumerator.Current;//當(dāng)前索引的值
                string str = (string)obj;
                Console.WriteLine(str);
            }
            enumerator.Reset();//恢復(fù)


            Console.ReadLine();
        }
    }
迭代器

迭代器其實(shí)就是對(duì)枚舉器的簡(jiǎn)化,使用迭代器,程序在編譯時(shí)自動(dòng)為我們創(chuàng)建枚舉器,枚舉器用到 yield return 或者 yield break
1、迭代器返回枚舉器

class MyClass : IEnumerable
    {
        public IEnumerator GetEnumerator()//在GetEnumerator方法中,返回枚舉器
        {
            return GetColor();//返回GetColor迭代器返回的枚舉器
        }
        public IEnumerator GetColor()//返回枚舉器
        {
            yield return "Red";
            yield return "Black";
            yield return "Green";
            yield return "Pink";
            yield return "Yellow";
        }
    }
class Program
    {
        static void Main(string[] args)
        {
            MyClass mc = new MyClass();
            foreach (var item in mc)
            {
                Console.Write(item + " ");
            }
            Console.ReadLine();
        }
    }

2、迭代器返回可枚舉類型

    class MyClass : IEnumerable
    {
        public IEnumerator GetEnumerator()//在GetEnumerator方法中,返回枚舉器
        {
            return GetColor().GetEnumerator();//通過(guò)調(diào)用GetColor返回的IEnumerable(可枚舉類型)的GetEnumerator方法,返回枚舉器
        }
        public IEnumerable GetColor()//返回可枚舉類型
        {
            yield return "Red";
            yield return "Black";
            yield return "Green";
            yield return "Pink";
            yield return "Yellow";
        }
    }
class Program
    {
        static void Main(string[] args)
        {
            MyClass mc = new MyClass();
            foreach (var item in mc)//直接調(diào)用MyClass中的GetEnumerator方法迭代
            {
                Console.Write(item + " ");
            }
            Console.WriteLine();
            foreach (var item in mc.GetColor())//調(diào)用MyClass中的GetColor方法返回的IEnumerable中的GetEnumerator方法迭代
            {
                Console.Write(item + " ");
            }
            Console.ReadLine();
        }
    }
迭代器作為屬性
 class MyClass : IEnumerable
    {
        bool b;
        public MyClass(bool b)
        {
            this.b = b;
        }
        public IEnumerator GetEnumerator()
        {
            return b ? GetColor1.GetEnumerator() : GetColor2.GetEnumerator();//通過(guò)b的位true或者false判斷調(diào)用哪個(gè)迭代器屬性
        }
        private IEnumerable GetColor1//迭代器屬性1
        {
            get
            {
                yield return "Red";
                yield return "Black";
                yield return "Green";
                yield return "Pink";
                yield return "Yellow";
            }
        }
        private IEnumerable GetColor2//迭代器屬性2
        {
            get
            {
                yield return "Yellow";
                yield return "Pink";
                yield return "Green";
                yield return "Black";
                yield return "Red";
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyClass mc = new MyClass(true);
            MyClass mc2 = new MyClass(false);
            foreach (var item in mc)
            {
                Console.Write(item + " ");
            }
            Console.WriteLine();
            foreach (var item in mc2)
            {
                Console.Write(item + " ");
            }

            Console.ReadLine();
        }
    }
迭代器的實(shí)質(zhì)

1、使用迭代器,需要引入System.Collections.Generic命名空間。
2、迭代器沒(méi)有實(shí)現(xiàn)枚舉器中的Resset方法,因此接口調(diào)用該方法時(shí)會(huì)拋出異常。
3、在后臺(tái),編譯器產(chǎn)生的枚舉器是包含4個(gè)狀態(tài)的狀態(tài)機(jī)
Befor:首次調(diào)用MoveNext的初始狀態(tài)
Running:調(diào)用MoveNext會(huì)進(jìn)入這個(gè)狀態(tài),在這個(gè)狀態(tài)中,枚舉器檢測(cè)并設(shè)置下一項(xiàng)的位置。在遇到y(tǒng)ield return或者yield break或迭代塊結(jié)束時(shí),退出狀態(tài)。
Suspende狀態(tài)機(jī)等待下次調(diào)用MoveNext狀態(tài)
After:沒(méi)有更多項(xiàng)可以枚舉。


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容