C# 9.0新特性——扩展方法GetEnumerator支持foreach循环

作者:markkang 时间:2021-08-27 22:38:09 

1.介绍

我们知道,我们要使一个类型支持foreach循环,就需要这个类型满足下面条件之一:

该类型实例如果实现了下列接口中的其中之一:

  • System.Collections.IEnumerable

  • System.Collections.Generic.IEnumerable<T>

  • System.Collections.Generic.IAsyncEnumerable<T>

该类型中有公开的无参GetEnumerator()方法,且其返回值类型必须是类,结构或者接口,同时返回值类型具有公共 Current 属性和公共无参数且返回类型为 Boolean的MoveNext 方法。

上面的第一个条件,归根结底还是第二个条件的要求,因为这几个接口,里面要求实现的还是GetEnumerator方法,同时,接口中GetEnumerator的返回值类型IEnumerator接口中要实现的成员和第二条中返回值类型的成员相同。

C#9.0之前,是不支持采取扩展方法的方式给类型注入GetEnumerator方法,以支持foreach循环的。从C#9.0之后,这种情况得到了支持。

2. 应用与示例

在这里,我们定义一个People类,它可以枚举其所有组员Person,并且在其中定义了MoveNext方法和Current属性。同时,我们也通过扩展方法给People注入了GetEnumerator方法。这样,我们就可以使用foreach来枚举People对象了。

首先,我们来定义一个Person记录:


public record Person(string FirstName, string LastName);

下来,我们来创建People类型,用来描述多个Person对象,并提供GetEnumerator返回值类型中所需的Current属性和MoveNext方法。在此,我们没有实现任何接口:


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方法。

然后,我们定义扩展方法,给People注入GetEnumerator方法


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循环,为特殊的需要提供了一种可能。

作者:MarkKang
出处:https://www.cnblogs.com/markkang/

来源:https://www.cnblogs.com/markkang/p/14018990.html

标签:c#,9.0,新特性,扩展方法,foreach,循环
0
投稿

猜你喜欢

  • Java 批量删除Word中的空白段落示例代码

    2023-09-17 16:36:53
  • springboot验证码生成以及验证功能举例详解

    2023-11-19 03:14:23
  • Java 替换字符串中的回车换行符的方法

    2022-10-05 10:55:22
  • maven profile实现多环境配置的示例

    2023-09-24 12:02:57
  • 详解java关于对象的比较

    2022-12-11 01:28:55
  • java中数组的定义及使用方法(推荐)

    2022-03-07 14:20:16
  • 解决Spring Batch框架job任务只跑一次的问题

    2023-01-07 00:13:53
  • Java中防止数据重复提交超简单的6种方法

    2022-03-18 11:03:22
  • spring-cloud-gateway动态路由的实现方法

    2021-07-25 15:24:37
  • Java使用Scanner类进行控制台输入实现方法

    2021-08-08 18:34:26
  • springboot整合mybatis-plus基于注解实现一对一(一对多)查询功能

    2021-06-16 13:08:29
  • Java中mybatis的三种分页方式

    2021-06-25 11:14:05
  • 一起来学习Java IO的转化流

    2023-11-26 20:38:30
  • spring循环注入异常问题的解决方案

    2021-06-29 02:21:18
  • Java Web项目中解决中文乱码方法总结(三种最新方法)

    2023-07-18 18:13:22
  • Java 中解决Unsupported major.minor version 51.0的问题

    2022-07-22 03:53:08
  • Springboot整合mqtt服务的示例代码

    2022-07-20 02:58:01
  • Java泛型之类型擦除实例详解

    2022-02-13 06:39:36
  • 从最基本的Java工程搭建SpringMVC+SpringDataJPA+Hibernate

    2023-05-31 20:37:20
  • C# ping网络IP 实现网络状态检测的方法

    2023-01-11 14:31:05
  • asp之家 软件编程 m.aspxhome.com