Table of contents
foreword
In the last article, I implemented a container C# study notes by myself – implementing a container that can repeat weights and can be automatically sorted – MultiplySortedSet
After writing, I suddenly thought of a question, how does the container traverse?
The for loop can use subscripts to traverse the array, but how does the for loop traverse the unordered collection? Then you have to use foreach .
But how does foreach traverse the collection? Since it is unordered, how do you find the next element?
With these questions, I have studied IEnumerable and IEnumerator .
IEnumerable 和 IEnumerator
What is IEnumerable?
Let's take a look at the definition of C#
namespace System.Collections
{
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
}
Simply put, the IEnumerable interface defines a GetEnumerator method that returns an object that implements the IEnumerator interface.
I definitely can't understand it at the first time, but we can try to translate
- IEnumerable: iterable
- Enumerator: iterator
Let's look at List and Dictionary again
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 and Dictionary can be traversed by foreach loop because they implement IEnumerable < T > and IEnumerable interfaces.
Having said that, I didn't say how to traverse it?
Don't worry, let's take a look at IEnumerator again
What is IEnumerator?
As usual, first look at the C# definition
namespace System.Collections
{
public interface IEnumerator
{
object Current {
get; }
bool MoveNext();
void Reset();
}
}
let's look at two things
- object Current { get; }
- bool MoveNext();
MoveNext , the translation is to move to the next one.
And Current is actually the current value.
It's useless to say more, just write a program to see
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);
}
}
}
The internal principle is actually like this, below is the pseudo code
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;
}
}
There is a pointer inside the iterator (of course, this pointer is not necessarily a pointer in C++, it is just a way of expression, of course, this pointer can also be the subscript of the array: index )
In our last example, the pointer initially pointed to NULL. That is, the index points to -1, and the Current is null
when we call MoveNext . That is, the index points to 0, at this time the Current is 1
and then MoveNext is called all the time ...
When index = 2 , that is, pointing to element 3
We call MoveNext again and find that there is no next element. At this time, MoveNext returns false
and the while loop is terminated.
Summarize
- The IEnumerable interface defines a GetEnumerator method that returns an object that implements the IEnumerator interface.
- Whereas the IEnumerator interface defines methods for traversing a sequence, such as MoveNext and Current .
ending trailer
In the next article, let's study how the foreach loop traverses the container