——委托
可以理解為:委托是一個(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)可以枚舉。
