C#迭代器局部變量
C#迭代器還是比較常見的東西,這里我們主要介紹C#迭代器局部變量,包括介紹C#里出現(xiàn)了foreach關(guān)鍵字等方面。
看看***的測試,是不是不管具體的集合如何改變,遍歷代碼都非常穩(wěn)定?而且擴(kuò)展新的集合類也非常方便,只是添加代碼不會修改原來的代碼,符合開閉原則。當(dāng)然,這么好的解決方案微軟當(dāng)然不會放過,現(xiàn)在C# 2.0里已經(jīng)內(nèi)置了對C#迭代器的支持,看看System.Collections, System.Collections.Generic命名空間,所有的集合都實(shí)現(xiàn)了這個(gè)接口:IEnumerable,這個(gè)接口還有泛型的版本。注意到這個(gè)接口只有一個(gè)方法:IEnumerator GetEnumerator();,IEnumerator就是C#迭代器的接口,相當(dāng)于我的實(shí)例里面的Iterator,它也有泛型的版本。
那么現(xiàn)在在.net里所有的集合類都可以這樣訪問了:
- IEnumerator ienumerator = list.GetEnumerator();
- while(ienumerator.MoveNext())
- {
- object current = ienumerator.Current;
- }
但是這樣訪問也太麻煩了,所以C#里出現(xiàn)了foreach關(guān)鍵字,我們來看看foreach背后發(fā)生了什么
- public static void Main()
- {
- ArrayList list = new ArrayList();
- list.Add(1);
- list.Add(2);
- list.Add(3);
- foreach (object item in list)
- {
- Console.WriteLine(item.ToString());
- }
- }
下面是它對應(yīng)的IL代碼:
- .method private hidebysig static void Main() cil managed
- {
- .entrypoint
- .maxstack 2
- .locals init (
- [0] class [mscorlib]System.Collections.ArrayList list,
- [1] object item,
- [2] class [mscorlib]System.Collections.IEnumerator CS$5$0000,
- [3] class [mscorlib]System.IDisposable CS$0$0001)
- L_0000: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
- L_0005: stloc.0
- L_0006: ldloc.0
- L_0007: ldc.i4.1
- L_0008: box int32
- L_000d: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
- L_0012: pop
- L_0013: ldloc.0
- L_0014: ldc.i4.2
- L_0015: box int32
- L_001a: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
- L_001f: pop
- L_0020: ldloc.0
- L_0021: ldc.i4.3
- L_0022: box int32
- L_0027: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
- L_002c: pop
- L_002d: ldloc.0
- L_002e: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]
- System.Collections.ArrayList::GetEnumerator()
- L_0033: stloc.2
- L_0034: br.s L_0048
- L_0036: ldloc.2
- L_0037: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
- L_003c: stloc.1
- L_003d: ldloc.1
- L_003e: callvirt instance string [mscorlib]System.Object::ToString()
- L_0043: call void [mscorlib]System.Console::WriteLine(string)
- L_0048: ldloc.2
- L_0049: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
- L_004e: brtrue.s L_0036
- L_0050: leave.s L_0063
- L_0052: ldloc.2
- L_0053: isinst [mscorlib]System.IDisposable
- L_0058: stloc.3
- L_0059: ldloc.3
- L_005a: brfalse.s L_0062
- L_005c: ldloc.3
- L_005d: callvirt instance void [mscorlib]System.IDisposable::Dispose()
- L_0062: endfinally
- L_0063: call string [mscorlib]System.Console::ReadLine()
- L_0068: pop
- L_0069: ret
- .try L_0034 to L_0052 finally handler L_0052 to L_0063
- }
從.locals init 那里可以看出編譯器為我們添加了兩個(gè)C#迭代器局部變量,一個(gè)就是C#迭代器。
- L_002d: ldloc.0
- L_002e: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]
- System.Collections.ArrayList::GetEnumerator()
- L_0033: stloc.2
這三行代碼告訴我們,調(diào)用list的GetEnumerator()方法,獲取C#迭代器實(shí)例將其賦值給編譯器為我們添加的那個(gè)C#迭代器局部變量,接著是L_0034: br.s L_0048,br.s這個(gè)指令是強(qiáng)制跳轉(zhuǎn),我們接著看
- L_0048: ldloc.2
- L_0049: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
【編輯推薦】