目录
- 前言
- 总结 IEnumerable 和 IEnumerator
- IEnumerable是什么?
- IEnumerator是什么?
- 总结
- 结尾预告
前言
上篇文章我是自己实现了一个容器C#学习笔记–实现一个可以重复权重并且能够自动排序的容器–MultiplySortedSet
写完之后突然想到一个问题,容器到底是怎么遍历的?
for循环可以用下标来进行遍历数组,但是for循环怎么遍历无序集合呢?那就得用foreach了。
但是foreach又是怎么进行集合的遍历呢?既然是无序的,那是怎么找到下一个元素的?
带着这些问题,我来研究了下IEnumerable和IEnumerator。
总结 IEnumerable 和 IEnumerator
IEnumerable是什么?
我们来看看C#的定义
namespace System.Collections
{
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
}
简单来说,IEnumerable接口定义了一个GetEnumerator方法,该方法返回一个实现了IEnumerator接口的对象。
第一次看肯定看不懂,不过我们可以试着翻译
- IEnumerable:可被迭代的
- Enumerator:迭代器
我们再来看看List和Dictionary
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
List和Dictionary是可以被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,此时 Current 为 null
当我们调用MoveNext的时候。也就是 index 指向0,此时 Current 为 1
然后一直调用MoveNext…
当 index = 2 的时候,也就是指向元素 3 的时候
我们再次调用MoveNext,发现没有下一个元素了,此时MoveNext返回false
那么while循环就被终止了。
总结
- IEnumerable接口定义了一个GetEnumerator方法,该方法返回一个实现了IEnumerator接口的对象。
- 而IEnumerator接口定义了用于遍历序列的方法,例如MoveNext和Current。
结尾预告
下篇文章我们来研究下foreach循环到底是怎么遍历容器的