您现在的位置是:主页 > news > 建设银行成都 招聘网站/5年网站seo优化公司
建设银行成都 招聘网站/5年网站seo优化公司
admin2025/5/30 12:59:54【news】
简介建设银行成都 招聘网站,5年网站seo优化公司,做网站是百度包年快照,网页布局基础为什么数组和集合可以使用foreach遍历 因为数组和集合都实现了IEnumerable接口,该接口中只有一个方法,GetEnumerator()。 数组类型是从抽象基类型 Array 派生的引用类型。由于此类型实现了 IEnumerable ,因此可以对 C# 中的所有数组使用 foreach 迭代。…
为什么数组和集合可以使用foreach遍历
因为数组和集合都实现了IEnumerable接口,该接口中只有一个方法,GetEnumerator()。
数组类型是从抽象基类型 Array 派生的引用类型。由于此类型实现了 IEnumerable ,因此可以对 C# 中的所有数组使用 foreach 迭代。
IEnumerable和IEnumerator接口定义
// 摘要:// 公开枚举器,该枚举器支持在非泛型集合上进行简单迭代。public interface IEnumerable{// 摘要:// 返回一个循环访问集合的枚举器。//// 返回结果:// 可用于循环访问集合的 System.Collections.IEnumerator 对象。IEnumerator GetEnumerator();}public interface IEnumerable<out T> : IEnumerable{new IEnumerator<T> GetEnumerator();}// 摘要:// 支持对非泛型集合的简单迭代。public interface IEnumerator{// 摘要:// 获取集合中的当前元素。//// 返回结果:// 集合中的当前元素。//// 异常:// System.InvalidOperationException:// 枚举数定位在该集合的第一个元素之前或最后一个元素之后。object Current { get; }// 摘要:// 将枚举数推进到集合的下一个元素。//// 返回结果:// 如果枚举数成功地推进到下一个元素,则为 true;如果枚举数越过集合的结尾,则为 false。//// 异常:// System.InvalidOperationException:// 在创建了枚举数后集合被修改了。bool MoveNext();//// 摘要:// 将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。//// 异常:// System.InvalidOperationException:// 在创建了枚举数后集合被修改了。void Reset();}public interface IEnumerator<out T> : IDisposable, IEnumerator{ new T Current { get; }}
Enumerator实现
[Serializable]public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator{private List<T> list;private int index;private int version;private T current;internal Enumerator(List<T> list) {this.list = list;index = 0;version = list._version;current = default(T);}public void Dispose() {}public bool MoveNext() {List<T> localList = list;if (version == localList._version && ((uint)index < (uint)localList._size)) { current = localList._items[index]; index++;return true;}return MoveNextRare();}private bool MoveNextRare(){ if (version != list._version) {ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);}index = list._size + 1;current = default(T);return false; }public T Current {get {return current;}}Object System.Collections.IEnumerator.Current {get {if( index == 0 || index == list._size + 1) {ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);}return Current;}}void System.Collections.IEnumerator.Reset() {if (version != list._version) {ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);}index = 0;current = default(T);}}
可以看到它实际上也是通过for循环去遍历的。
对于List集合.NET是怎么实现这个IEnumerable接口的
以泛型List为例,它继承了IList<T>接口,而IList<T>继承了ICollection<T>接口,ICollection<T>继承了IEnumerable<T>这个接口。
找到它的具体实现,实际上是返回了一个枚举器,通过此枚举器完成对列表元素的遍历。
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{return new Enumerator(this);
}
也就是说,实际上foreach的原型代码实际上可以写成
IEnumerator enumerator = list.GetEnumerator();
while(enumerator.MoveNext())
{Debug.Log(enumerator.Current);
}
如何自定义一个类型使它可以使用foreach去遍历
例如有这样一个类Person:
public class Person
{public Person(string fName, string lName){this.firstName = fName;this.lastName = lName;}public string firstName;public string lastName;
}
定义另一个类People来实现IEnumerable迭代器完成对Person的迭代,在返回枚举器时返回的是实现了IEnumerator的PeopleEnum类型实例:
public class People : IEnumerable
{private Person[] _people;public People(Person[] pArray){_people = new Person[pArray.Length];for (int i = 0; i < pArray.Length; i++){_people[i] = pArray[i];}}//Implementation for the GetEnumerator method.IEnumerator IEnumerable.GetEnumerator(){return (IEnumerator) GetEnumerator();}public PeopleEnum GetEnumerator(){return new PeopleEnum(_people);}
}
public class PeopleEnum : IEnumerator
{public Person[] _people;// Enumerators are positioned before the first element// until the first MoveNext() call.int position = -1;public PeopleEnum(Person[] list){_people = list;}public bool MoveNext(){position++;return (position < _people.Length);}public void Reset(){position = -1;}object IEnumerator.Current{get{return Current;}}public Person Current{get{try{return _people[position];}catch (IndexOutOfRangeException){throw new InvalidOperationException();}}}
}
实际应用时:
Person[] peopleArray = new Person[3]{new Person("John", "Smith"),new Person("Jim", "Johnson"),new Person("Sue", "Rabon"),};People peopleList = new People(peopleArray);foreach (Person p in peopleList)Console.WriteLine(p.firstName + " " + p.lastName);
配合yield关键字可以通过更简易的方式来创建枚举器
public class People : IEnumerable
{private Person[] _people;public People(Person[] pArray){_people = new Person[pArray.Length];for (int i = 0; i < pArray.Length; i++){_people[i] = pArray[i];}}// Implementation for the GetEnumerator method.IEnumerator IEnumerable.GetEnumerator(){for (int i = 0; i < _people.Length; i++){yield return _people[i];}}}
yield和return一起使用才有意义,这个关键字就是为迭代器服务的,所以有yield所在的方法是迭代器。yield关键字其实是一种语法糖,最终还是通过实现IEnumberable<T>、IEnumberable、IEnumberator<T>和IEnumberator接口实现的迭代功能。