C#学习笔记--由浅至深理解IEnumerable和IEnumerator

前言

上篇文章我是自己实现了一个容器C#学习笔记–实现一个可以重复权重并且能够自动排序的容器–MultiplySortedSet

写完之后突然想到一个问题,容器到底是怎么遍历的?
for循环可以用下标来进行遍历数组,但是for循环怎么遍历无序集合呢?那就得用foreach了。
但是foreach又是怎么进行集合的遍历呢?既然是无序的,那是怎么找到下一个元素的?
带着这些问题,我来研究了下IEnumerableIEnumerator

IEnumerable 和 IEnumerator

IEnumerable是什么?

我们来看看C#的定义

namespace System.Collections
{
    
    
    public interface IEnumerable
    {
    
    
        IEnumerator GetEnumerator();
    }
}

简单来说,IEnumerable接口定义了一个GetEnumerator方法,该方法返回一个实现了IEnumerator接口的对象。

第一次看肯定看不懂,不过我们可以试着翻译

  • IEnumerable:可被迭代的
  • Enumerator:迭代器

我们再来看看ListDictionary

public class List<T> : ICollection<T>, IEnumerable<T>, IEnumerable, IList<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection, IList
public class Dictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, IReadOnlyDictionary<TKey, TValue>, ICollection, IDictionary, IDeserializationCallback, ISerializable

ListDictionary是可以被foreach循环遍历的,原因就是它们实现了IEnumerable < T > IEnumerable接口。

说了这些,也没有说到底是怎么遍历的呀?
不急,我们再来看看IEnumerator

IEnumerator是什么?

老样子,先看C#定义

namespace System.Collections
{
    
    
    public interface IEnumerator
    {
    
    
        object Current {
    
     get; }

        bool MoveNext();
        void Reset();
    }
}

我们来看两个东西

  • object Current { get; }
  • bool MoveNext();

MoveNext,翻译过来就是移动到下一个。
Current其实就是当前的值。

多说无益,直接写个程序来看看

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
    
    
    private void Awake()
    {
    
    
        int[] array = new int[3] {
    
     1, 2, 3 };
        var it = array.GetEnumerator();//获取对象的迭代器

        while (it.MoveNext())
        {
    
    
            print(it.Current);
        }
    }
}

在这里插入图片描述
内部原理其实是这样的,下方是伪代码

private int index = -1;
private int[] array;

public int Current
{
    
    
    get
    {
    
    
    	if(index == -1) return null;
        return array[index];
    }
}

public bool MoveNext()
{
    
    
	if(index < array.Length)
	{
    
    
		index++;
		return true;
	}
	else
	{
    
    
		return false;
	}
}

迭代器内部有一个指针(当然这个指针不一定是C++中的指针,只是一种表达方式,当然这个指针也可以是数组的下标:index

在我们的上个例子中,初始的时候指针指向空。也就是 index 指向-1,此时 Currentnull
在这里插入图片描述
当我们调用MoveNext的时候。也就是 index 指向0,此时 Current1
在这里插入图片描述
然后一直调用MoveNext

index = 2 的时候,也就是指向元素 3 的时候
在这里插入图片描述

我们再次调用MoveNext,发现没有下一个元素了,此时MoveNext返回false
那么while循环就被终止了。

总结

  • IEnumerable接口定义了一个GetEnumerator方法,该方法返回一个实现了IEnumerator接口的对象。
  • IEnumerator接口定义了用于遍历序列的方法,例如MoveNextCurrent

结尾预告

下篇文章我们来研究下foreach循环到底是怎么遍历容器的

猜你喜欢

转载自blog.csdn.net/qq_52855744/article/details/130601250