咱们知道,咱们要使一个类型支持foreach循环,就须要这个类型知足下面条件之一:测试
该类型实例若是实现了下列接口中的其中之一:this
该类型中有公开的无参GetEnumerator()方法,且其返回值类型必须是类,结构或者接口,同时返回值类型具备公共 Current 属性和公共无参数且返回类型为 Boolean的MoveNext 方法。code
上面的第一个条件,归根结底仍是第二个条件的要求,由于这几个接口,里面要求实现的仍是GetEnumerator方法,同时,接口中GetEnumerator的返回值类型IEnumerator接口中要实现的成员和第二条中返回值类型的成员相同。对象
C#9.0以前,是不支持采起扩展方法的方式给类型注入GetEnumerator方法,以支持foreach循环的。从C#9.0以后,这种状况获得了支持。接口
在这里,咱们定义一个People类,它能够枚举其全部组员Person,而且在其中定义了MoveNext方法和Current属性。同时,咱们也经过扩展方法给People注入了GetEnumerator方法。这样,咱们就可使用foreach来枚举People对象了。get
首先,咱们来定义一个Person记录:string
public record Person(string FirstName, string LastName);
下来,咱们来建立People类型,用来描述多个Person对象,并提供GetEnumerator返回值类型中所需的Current属性和MoveNext方法。在此,咱们没有实现任何接口:it
public class People:IDisposable//: IEnumerator<Person> { int position = -1; private Person[] _people { get; init; } public People(Person[] people) { _people = people; } public bool MoveNext() { position++; return (position < _people.Length); } public Person Current { get { try { return _people[position]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } public void Reset() { position = -1; } public void Dispose() { Reset(); } }
须要注意的是People中,因为没有经过使用前面的接口来实现支持foreach功能,这样就存在一个问题,就是第一次foreach循环完成后,状态尚未恢复到初始状态,第二次使用foreach进行枚举就没有可用项。所以咱们添加了Reset方法用于手工恢复回初始状态,若是想让foreach能自动恢复状态,就让People实现接口IDisposable,并在其实现中,调用Reset方法。io
而后,咱们定义扩展方法,给People注入GetEnumerator方法ast
static class PeopleExtensions { //public static IEnumerator<T> GetEnumerator<T>(this IEnumerator<T> people) => people; public static People GetEnumerator(this People people) => people; }
最后,只要引用了扩展方法所在的命名空间,foreach循环就可使用了。
var PersonList = new Person[3] { new ("John", "Smith"), new ("Jim", "Johnson"), new ("Sue", "Rabon"), }; var people = new People(PersonList); foreach (var person in people) { Console.WriteLine(person); }
到这里,咱们就完成了利用扩展方法来实现foreach循环的示例,为了方便拷贝测试,咱们全部的代码放在一块儿就以下所示:
var PersonList = new Person[3] { new ("John", "Smith"), new ("Jim", "Johnson"), new ("Sue", "Rabon"), }; var people = new People(PersonList); foreach (var person in people) { Console.WriteLine(person); } public record Person(string FirstName, string LastName); public class People:IDisposable//: IEnumerator<Person> { int position = -1; private Person[] _people { get; init; } public People(Person[] people) { _people = people; } public bool MoveNext() { position++; return (position < _people.Length); } public Person Current { get { try { return _people[position]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } public void Reset() { position = -1; } public void Dispose() { Reset(); } } static class PeopleExtensions { //public static IEnumerator<T> GetEnumerator<T>(this IEnumerator<T> people) => people; public static People GetEnumerator(this People people) => people; }
解除原有的限制,扩展方法GetEnumerator支持foreach循环,为特殊的须要提供了一种可能。
如对您有价值,请推荐,您的鼓励是我继续的动力,在此万分感谢。关注本人公众号“码客风云”,享第一时间阅读最新文章。