探讨关于C#中Foreach的本质
一.为什么数组和集合可以使用foreach遍历
01. 因为数组和集合都实现了IEnumerable接口,该接口中只有一个方法,GetEnumerator(),返回值是IEnumerator 接口类型。
我们来探讨一下IEnumerable接口、IEnumerator
IEnumerable接口
只有一个 返回值为IEnumerator 接口类型的GetEnumerator()方法
public System.Collections.IEnumerator GetEnumerator ();
IEnumerator接口
有2个 方法、一个属性。
属性
Current |
获取集合中位于枚举数当前位置的元素。 |
public object Current { get; }
方法
MoveNext() |
将枚举数推进到集合的下一个元素。 |
Reset() |
将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。 |
public bool MoveNext (); public void Reset ();
了解完foreach原理我们来给自定义的集合类实现foreach的功能,类图设计如下,给班级实现foreach学生的功能:
代码如下:
using System; using System.Collections; using System.Collections.Generic; namespace School { /// <summary> /// 测试 /// </summary> public class Test { static void Main() { ClassOfStudent cof = new (); cof.AddStudent(new() { Name = "小明", Age = 15, Height = "165cm" }); cof.AddStudent(new() { Name = "小s明", Age = 15, Height = "165cm" }); cof.AddStudent(new() { Name = "王明", Age = 15, Height = "165cm" }); foreach (Student ddfd in cof) { Console.WriteLine(ddfd); } } } /// <summary> /// 学生 /// </summary> public class Student : Person,IComparable<Student> { private int dage; public int Dage { get => dage; set => dage = value; } //重载比较方法 public int CompareTo(Student st) { return this.Name.CompareTo(st.Name); } //重载 ToString()方法 public override string ToString() { return string.Format($"姓名:{this.Name} 年龄:{this.Age}"); } } /// <summary> /// 班级 /// </summary> public class ClassOfStudent : Person, IEnumerable { private string className; private int studentNumber; private readonly List<Student> students=new(); public string ClassName { get => className; set => className = value; } public int StudentNumber { get => studentNumber; set => studentNumber = value; } public Student this[string name] { get => students.Find(x => x.Name.Contains(name)); } public void AddStudent(Student st) { students.Add(st); } public IEnumerator GetEnumerator() { return (IEnumerator)(new StudentEnumerator(students)); } } /// <summary> /// 枚举学生的类 /// </summary> public class StudentEnumerator : IEnumerator { public List<Student> students; int position = -1; public void Reset() => position = -1; public StudentEnumerator(List<Student> st) { students = st; } public bool MoveNext() { position++; return (position < students.Count); } object IEnumerator.Current { get { return students[position]; } } } /// <summary> /// 人 的共同特征 年龄 姓名 性别等 /// </summary> public abstract class Person { private string name; private string height; private int age; public string Name { get => name; set { if (string.IsNullOrEmpty(value)) throw new ArgumentException("不能使用空白名称", "Name"); name = value; } } public string Height { get => height; set => height = value; } public int Age { get => age; set => age = value; } public override string ToString() { return name; } } }