ForEach 是一個循環結構,但是卻不像 for 一樣使用下標。
它用於 數組 和 集合 的遍歷。
1、數組的遍歷
int[] arr = new int[]{1, 2, 3, 4};
foreach(int element in arr)
{
Console.WriteLine(element);
}
2、集合的遍歷
using System.Collections;
...
ArrayList list = new ArrayList();
list.Add("hello");
list.Add("guys");
foreach(string e in list)
{
Console.WriteLine(e);
}
3、泛型集合的遍歷
using System.Collections.Generic;
...
List<int> list = new List<int>();
list.Add(1);
list.Add(3);
list.Add(5);
foreach(int e in list)
{
Console.WriteLine(e);
}
注意:雖然,ForEach 和 For 一樣都是循環結構,但是,它們之間比較大的區別就在於,在Foreach內部是不能對 元素進行修改的,否則會發生編譯錯誤。
ForEach中的變量是ReadOnly變量。
foreach(int e in list)
{
if(e == 3)
{
e = 6; //導致編譯錯誤,不能修改,因爲是 只讀 變量
}
}
如果,想要對遍歷 數組或集合中的數據進行修改的話,就 改用 for 循環吧!
有時,我們不僅希望能夠在 數組 和集合中使用 Foreach 循環,我們還希望對我們自定義的類使用ForEach循環。
什麼意思呢?就是,對自定義的類的使用 Foreach循環,獲取內部的元素。
這時,對於自定義的類,需要去繼承 IEnumerable 或者 IEnumerable<T> 接口,就可以了。
IEnumetable 接口中 只有一個方法IEnumerator GetEnumerator()
由於返回值爲 IEnumerator 意味着,我們還需要去 定義一個類 繼承IEnumerator 接口。
IEnumerator 是所有非泛型枚舉數的基接口。枚舉數可用於讀取集合中的數據,但不能用於修改基礎集合
在IEnumerator中,有三個東西 需要我們去實現,分別是 bool MoveNext(), void Reset(), object Current.
public class Person
{
string name;
int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public override string ToString()
{
return this.name + " " + this.age;
}
}
public class People : IEnumerable
{
private Person[] people;
public People(Person[] _people)
{
people = new Person[_people.Length];
for (int i = 0; i < _people.Length; i++)
{
people[i] = _people[i];
}
}
public IEnumerator GetEnumerator()
{
return (IEnumerator)new PeopleEnumerator(this);
}
public class PeopleEnumerator : IEnumerator
{
private People p;
private int position = -1;
public PeopleEnumerator(People p)
{
this.p = p;
}
public bool MoveNext()
{
if (position < p.people.Length - 1)
{
position++;
return true;
}
else
{
return false;
}
}
public void Reset()
{
position = -1;
}
public object Current
{
get { return this.p.people[position]; }
}
}
static void Main()
{
Person[] Persons = new Person[] { new Person("kim", 20), new Person("tim", 23) };
People p = new People(Persons);
foreach (object obj in p) {
Person o = (Person)obj;
Console.WriteLine(o);
}
Console.ReadKey(true);
}
}
其實,我們不用實現 IEnumerable 接口也能夠使用 Foreach循環。只要在 類中有 GetEnumerator()方法和一個具有
MoveNext()、Reset()、Current 這三個東西的類,同樣能夠能行!
代碼示例:
public class Person
{
string name;
int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public override string ToString()
{
return this.name + " " + this.age;
}
}
public class People
{
private Person[] people;
public People(Person[] _people)
{
people = new Person[_people.Length];
for (int i = 0; i < _people.Length; i++)
{
people[i] = _people[i];
}
}
public PeopleEnumerator GetEnumerator()
{
return new PeopleEnumerator(this);
}
public class PeopleEnumerator
{
private People p;
private int position = -1;
public PeopleEnumerator(People p)
{
this.p = p;
}
public bool MoveNext()
{
if (position < p.people.Length - 1)
{
position++;
return true;
}
else
{
return false;
}
}
public void Reset()
{
position = -1;
}
public Person Current
{
get { return this.p.people[position]; }
}
}
static void Main()
{
Person[] Persons = new Person[] { new Person("kim", 20), new Person("tim", 23) };
People p = new People(Persons);
foreach (Person mate in p){
Console.WriteLine(mate);
}
Console.ReadKey(true);
}
}
上例中,沒有再繼承 IEnumerable 接口,但是得到了相同的結果。但是書上說,這個還能夠改進,兩者同時使用。
但是,我不太懂它的含義就,暫且擱置!