C#從foreach語句中枚舉元素看數(shù)組詳解
前言
在foreach語句中使用枚舉,可以迭代數(shù)組或集合中的元素,且無須知道集合中的元素的個(gè)數(shù)。如圖顯示了調(diào)用foreach方法的客戶端和集合之間的關(guān)系。數(shù)組或集合實(shí)現(xiàn)帶GetEnumerator()
方法的IEnumerable接口。GetEnumerator()
方法返回一個(gè)實(shí)現(xiàn)lEnumerable接口的枚舉,接著foreach語句就可以使用IEnumerable接口迭代集合了。
GetEnumerator()
方法用IEnumerable接口定義,foreach語句并不真的需要在集合類中實(shí)現(xiàn)這個(gè)接口。有一個(gè)名為GetEnumerator()
的方法它返回實(shí)現(xiàn)了IEnumerator接口的對(duì)象就足夠了。
先定義一個(gè)Person類,這個(gè)類有自動(dòng)實(shí)現(xiàn)的屬性Firstname和Lastname,以及從Object類重寫ToString方法和繼承泛型接口IEquatable以比較兩個(gè)對(duì)象是否相等,實(shí)現(xiàn)泛型接口IComparer以比較兩個(gè)對(duì)象用來排序。
public class Person : IEquatable<Person>,IComparable<Person> { public int Id { get; private set; } public string FirstName { get; set; } public string LastName { get; set; } public override string ToString() { return String.Format("{0}, {1} {2}", Id, FirstName, LastName); } public bool Equals(Person other) { if (other == null) return base.Equals(other); return this.FirstName == other.FirstName && this.LastName == other.LastName; } public int CompareTo(Person other) { if (other == null) throw new ArgumentNullException("other"); int result = this.LastName.CompareTo(other.LastName); if (result == 0) { result = this.FirstName.CompareTo(other.FirstName); } return result; } }
創(chuàng)建一個(gè)三個(gè)元素的person數(shù)組,現(xiàn)對(duì)數(shù)組進(jìn)行排序在用foreach循環(huán)訪問數(shù)組中的元素并輸出
Person[] persons = { new Person { FirstName = "Simen03", LastName = "Go" }, new Person { FirstName = "Simen02", LastName = "Go" }, new Person { FirstName = "Simen01", LastName = "Go" } }; Array.Sort(persons); foreach (var person in persons) Console.WriteLine(person);
分析foreach (var person in persons)Console.WriteLine(person);
這段代碼IL代碼
// loop start (head: IL_009b) IL_008a: ldloc.2 IL_008b: ldloc.3 IL_008c: ldelem.ref IL_008d: stloc.s person IL_008f: ldloc.s person IL_0091: call void [mscorlib]System.Console::WriteLine(object) IL_0096: nop IL_0097: ldloc.3 IL_0098: ldc.i4.1 IL_0099: add IL_009a: stloc.3 IL_009b: ldloc.3 IL_009c: ldloc.2 IL_009d: ldlen IL_009e: conv.i4 IL_009f: blt.s IL_008a // end loop
C#的foreach語句不會(huì)解析為IL代碼中的foreach語句,C#編譯器會(huì)把foreach語句轉(zhuǎn)換為IEnumerable接口的方法和屬性,foreach語句使用IEnumerator接口的方法和屬性,迭代數(shù)組中的所有元素,為此,IEnumerator定義了Current屬性,來返回光標(biāo)所在的元素,該接口的MoveNext()
方法移動(dòng)到數(shù)組的下一個(gè)元素上,如果有這個(gè)元素該方法就返回true否則返回false,這個(gè)接口的泛型版本IEnumerator派生自接口IDisposable,因此定義了Dispose()
方法來清理枚舉器占用的資源,使用foreach語句會(huì)解析為下面的代碼段
IEnumerator enumerator = persons.GetEnumerator(); while (enumerator.MoveNext()) { var person = enumerator.Current; Console.WriteLine(person); }
為了方便的創(chuàng)建枚舉器,C#添加了yield語句,yield return 語句返回集合的一個(gè)元素,并移動(dòng)到下一個(gè)元素,yield break 可停止迭代。使用迭代塊,編譯器會(huì)生成一個(gè)yield類型,其中包含一個(gè)狀態(tài)機(jī),如下代碼段所示。yield 類型實(shí)現(xiàn)IEnumerator和IDisposable接口的屬性和方法。在下面的例子中,可以把yield類型看作內(nèi)部類Enumerator.外部類的GetEnumerator()
方法實(shí)例化并返回一個(gè)新的yield類型。在yield類型中,變量state定義了迭代的當(dāng)前位置,每次調(diào)用MoveNext()
時(shí),當(dāng)前位置都會(huì)改變,MoveNext()
封裝了迭代代碼,并設(shè)置了current變量的值,從而使Current屬性根據(jù)位置返回一個(gè)對(duì)象。
static void Main(string[] args) { var helloCollection = new HelloCollection(); foreach (string s in helloCollection) { Console.WriteLine(s); } } public class HelloCollection { public IEnumerator<string> GetEnumerator() { yield return "Hello"; yield return "World"; } } public class HelloCollectionOther { public IEnumerator GetEnumertor() { return new Enumerator(0); } public class Enumerator : IEnumerator<string>, IEnumerator, IDisposable { private int state; private string current; public Enumerator(int state) { this.state = state; } public string Current => throw new NotImplementedException(); object IEnumerator.Current { get { return current; } } public void Dispose() { throw new NotImplementedException(); } public bool MoveNext() { switch (state) { case 0:current = "hello"; state = 1; return true; case 1:current = "world"; state = 2; return true; case 2: break; } return false; } public void Reset() { throw new NotImplementedException(); } } }
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
C#利用GDI+繪制旋轉(zhuǎn)文字等效果實(shí)例
這篇文章主要介紹了C#利用GDI+繪制旋轉(zhuǎn)文字等效果實(shí)例,是非常實(shí)用的重要技巧,需要的朋友可以參考下2014-09-09基于c#用Socket做一個(gè)局域網(wǎng)聊天工具
目前基于Internet的即時(shí)聊天工具已經(jīng)做的非常完美,本文介紹了基于c#用Socket做一個(gè)局域網(wǎng)聊天工具,有需要的朋友可以看一下。2016-10-10基于c#圖像灰度化、灰度反轉(zhuǎn)、二值化的實(shí)現(xiàn)方法詳解
本篇文章是對(duì)c#圖像灰度化、灰度反轉(zhuǎn)、二值化的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C#實(shí)現(xiàn)控制電腦注銷,關(guān)機(jī)和重啟
這篇文章主要為大家介紹了C#如何實(shí)現(xiàn)控制電腦注銷,關(guān)機(jī)和重啟功能,本案例涉及的知識(shí)點(diǎn)包含:Process、Shell32.dll、User32.dll、Struct數(shù)據(jù)結(jié)構(gòu),感興趣的可以了解一下2022-09-09Unity?UGUI的PhysicsRaycaster物理射線檢測(cè)組件介紹使用
這篇文章主要介紹了Unity?UGUI的PhysicsRaycaster物理射線檢測(cè)組件的介紹及使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07C# Entity Framework中的IQueryable和IQueryProvider詳解
這篇文章主要介紹了C# Entity Framework中的IQueryable和IQueryProvider詳解,本文使用實(shí)例分析這兩個(gè)接口的內(nèi)部實(shí)現(xiàn),需要的朋友可以參考下2015-01-01C#實(shí)現(xiàn)自定義動(dòng)畫鼠標(biāo)的示例詳解
這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)自定義動(dòng)畫鼠標(biāo)效果,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下2022-12-12解決unity3d導(dǎo)入模型貼圖材質(zhì)丟失的問題
這篇文章主要介紹了解決unity3d導(dǎo)入模型貼圖材質(zhì)丟失的問題,具有很好的參考價(jià)值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-04-04