C#编程(三十五)----------foreach和yield
枚舉
在foreach語句中使用枚舉,可以迭代集合中的元素,且無需知道集合中的元素個數.
數組或集合實現帶GetEumerator()方法的IEumerable接口.GetEumerator()方法返回一個實現IEunmerable接口的枚舉.
GetEnumerator()方法用IEnumerable接口定義.foreach語句并不真的需要在集合類中實現這個借口.有一個名為GetEnumerator()的方法,他返回實現了IEnumerator接口的對象就足夠了.
?
IEnumerator接口
foreach語句使用IEnumerator接口的方法和屬性,迭代集合中的所有元素.為此IEnumerator定義了Current屬性,來返回光標所在的元素,該接口的MoveNext()方法移動到集合的下一個元素上,如果有這個元素,該方法就返回true.如果集合不再有更多的元素,該方法就返回false.
這個借口的泛型版本IEnumerator<T>派生自接口IDisposable,因此定義了Dispose()方法,來清理枚舉器占用的資源.
?
foreach語句
C#的foreach語句不會解釋為IL代碼中的foreach語句.C#編譯器會把foreach語句轉換為IEnumerable接口的方法和屬性.案例:
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8 };
foreach (var item in arr)
{
???? Console.WriteLine(item);
}
很明顯,foreach語句很簡潔,但是他的有點不僅僅在于此,它的效率也是很高的,不用考慮數組是幾維的.案例:
int[,] array = new int[8, 8];
??????????? for (int i = 0; i < array.GetLength(0); i++)
??????????? {
??????????????? for (int j = 0; j < array.GetLength(1); j++)
??????????????? {
Console.WriteLine(array[i,j].ToString());
??????????????? }
??????????? }
??????????? Console.ReadKey();
使用foreach:
foreach (int item in array)
??????????? {
??????????????? Console.WriteLine(item.ToString());
??????????? }
對于三維或者更多維,foreach語句不用發生任何變化,而對于for語句就要進行修改了.
?
foreach完成類型轉換操作,案例:
int[] array = new int[100];
??????????? ArrayList aList = new ArrayList();
??????????? aList.AddRange(array);
??????????? foreach (int item in aList)
??????????? {
??????????????? Console.WriteLine(item.ToString());
??????????? }
??????????? for (int i = 0; i < aList.Count; i++)
??????????? {
??????????????? int n = (int)aList[i];
??????????????? Console.WriteLine(n.ToString());
??????????? }
??????????? Console.ReadKey();
?
foreach并沒有增加資源使用,由于對于繼承了IEnumerable接口的數據類型,才能使用foreach語句,那么對于使用foreach會訪問IEnumerable接口中的GetEnumerator()方法來進行枚舉,那么對應如上的foreach語句,對應的語句如下:
IEnumerator it = aList.GetEnumerator() as IEnumerator;
??????????? using (IDisposable disp = it as IDisposable)
??????????? {
??????????????? while (it.MoveNext())
??????????????? {
??????????????????? int elem = (int)it.Current;
??????????????????? Console.WriteLine(elem.ToString());
??????????????? }
??????????? }
也即是說再出了foreach語句之后對于IEnumerator的對象也進行IDispose處理.
?
foreach的兩種限制
不能修改枚舉成員:
int[] array = new int[100];
??????????? foreach (var item in array)
??????????? {
??????????????? item++;//這是錯誤的,因為枚舉成員是只讀的
??????????????? Console.WriteLine(item.ToString());
??????????? }
不要對集合進項刪除操作:
int[] array = new int[100];
??????????? ArrayList alist = new ArrayList();
??????????? alist.AddRange(array);
??????????? foreach (var item in alist)
??????????? {
??????????????? alist.Remove(item);//這是錯誤的
??????????????? Console.WriteLine(item.ToString());
??????????? }
對于刪除成員和修改成員可以使用for循環來處理,對于一個記錄集的多條數據刪除問題,也是經常出現的問題,由于在一些記錄集中進行刪除的時候,在刪除操作之后相應的索引也發生了變化,這時候的刪除要反過來進行刪除:
int[] array = new int[100];
??????????? ArrayList alist = new ArrayList();
??????????? alist.AddRange(array);
??????????? for (int i = alist.Count-1; i >=0; i--)
??????????? {
??????????????? int n = (int)alist[i];
??????????????? if (n==5)
??????????????? {
??????????????????? alist.RemoveAt(i);
??????????????? }
??????????????? Console.WriteLine(n.ToString());
??????????? }
?
除了上述提到的foreach的兩個約束外,foreach可以用于人和循環.
?
yield語句
C#中的yield語句便于創建枚舉器.
yield語句的兩種形式:
1.yield return <expression>
2.yield break;
?
使用一個yield return語句返回集合的一個元素
包含yield語句的方法或屬性是迭代器.迭代器必須滿足下列要求:
a.返回類型必須是IEnumerable,IEnumerable<T>,IEnumerator或IEnumerator<T>
b.他不能有任何ref或out參數.
?
yield return語句不能位于try-catch塊;yield return語句可以位于try-finally的try中
yield return語句返回集合的一個元素,并移動到下一個元素上.yield break可以停止迭代.
?
class Program
??? {
??????? static void Main(string[] args)
??????? {
??????????? HelloCollection hello = new HelloCollection();
??????????? foreach(string item in hello)
??????????? {
??????????????? Console.WriteLine(item);????????????????
??????????? }
??????????? Console.ReadKey();??
??????? }
?
??? }
??? public class HelloCollection
??? {
??????? public? IEnumerator<string> GetEnumerator()
??????? {
??????????? //yield return語句返回集合的一個元素,并移動到下一個元素上
??????????? //yield break可以終止迭代
??????????? yield return "hello";
??????????? yield return "world";
??????? }
}
?
使用yield return語句實現以不同方式迭代集合的類:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
?
namespace 枚舉
{
??? class Program
??? {
??????? static void Main(string[] args)
??????? {
??????????? MusicTitles music = new MusicTitles();
??????????? foreach(var item in music.GetEnumerator())
??????????? {
??????????????? Console.WriteLine(item);
??????????? }
??????????? Console.WriteLine();
??????????? foreach (string item in music.Reverse())
??????????? {
??????????????? Console.WriteLine(item);
??????????? }
??????????? Console.WriteLine();
??????????? foreach (var item in music.Subset(2,2))
??????????? {
??????????????? Console.WriteLine(item);
??????????? }
??????????? Console.ReadKey();??
??????? }
?
??? }
??? public class MusicTitles
??? {
??????? string[] names = {"a","b","c","d" };
??????? public IEnumerable<string> GetEnumerator()
??????? {
??????????? foreach (string item in names)
??????????? {
??????????????? yield return item;
??????????? }
??????? }
??????? public IEnumerable<string> Reverse()
??????? {
??????????? for (int i = 3; i >=0; i--)
??????????? {
??????????????? yield return names[i];
??????????? }
??????? }
??????? public IEnumerable<string> Subset(int index, int offert)
??????? {
??????????? for (int i = index; i < index+offert; i++)
??????????? {
??????????????? yield return names[i];
??????????? }
??????? }
??? }
}
轉載于:https://www.cnblogs.com/FinleyJiang/p/7602577.html
總結
以上是生活随笔為你收集整理的C#编程(三十五)----------foreach和yield的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 系统思考与《第五项修炼》
- 下一篇: 翁恺第三周2题