Table des matières
avant-propos
Dans le dernier article, j'ai implémenté moi-même un conteneur de notes d'étude C # - implémentant un conteneur qui peut répéter les poids et peut être trié automatiquement - MultiplySortedSet
Après avoir écrit, j'ai soudainement pensé à une question, comment le conteneur traverse-t-il ?
La boucle for peut utiliser des indices pour parcourir le tableau, mais comment la boucle for traverse-t-elle la collection non ordonnée ? Ensuite, vous devez utiliser foreach .
Mais comment foreach traverse-t-il la collection ? Puisqu'il n'est pas ordonné, comment trouvez-vous l'élément suivant ?
Avec ces questions, j'ai étudié IEnumerable et IEnumerator .
IEnumerable 和 IEnumerator
Qu'est-ce que IEnumerable ?
Jetons un coup d'œil à la définition de C #
namespace System.Collections
{
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
}
En termes simples, l'interface IEnumerable définit une méthode GetEnumerator qui renvoie un objet qui implémente l'interface IEnumerator .
Je ne peux certainement pas le comprendre du premier coup, mais nous pouvons essayer de traduire
- IEnumerable : itérable
- Énumérateur : itérateur
Regardons à nouveau la liste et le dictionnaire
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 et Dictionary peuvent être parcourus par la boucle foreach car ils implémentent les interfaces IEnumerable < T > et IEnumerable .
Cela dit, je n'ai pas dit comment le parcourir?
Ne vous inquiétez pas, regardons à nouveau IEnumerator
Qu'est-ce qu'IEnumerator ?
Comme d'habitude, regardez d'abord la définition C #
namespace System.Collections
{
public interface IEnumerator
{
object Current {
get; }
bool MoveNext();
void Reset();
}
}
regardons deux choses
- objet Courant { obtenir ; }
- bool MoveNext();
MoveNext , la traduction consiste à passer au suivant.
Et Current est en fait la valeur actuelle.
Inutile d'en dire plus, il suffit d'écrire un programme pour voir
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);
}
}
}
Le principe interne est en fait comme ça, ci-dessous le 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;
}
}
Il y a un pointeur à l'intérieur de l'itérateur (bien sûr ce pointeur n'est pas forcément un pointeur en C++, c'est juste un moyen d'expression, bien sûr ce pointeur peut aussi être l'indice du tableau : index )
Dans notre dernier exemple, le pointeur pointait initialement sur NULL. Autrement dit, l'index pointe vers -1 et Current est nul
lorsque nous appelons MoveNext . C'est-à-dire que l'index pointe vers 0, à ce moment le Current est 1
et ensuite MoveNext est appelé tout le temps ...
Lorsque index = 2 , c'est-à-dire pointant vers l'élément 3
Nous appelons à nouveau MoveNext et constatons qu'il n'y a pas d'élément suivant. À ce moment, MoveNext renvoie false
et la boucle while est terminée.
Résumer
- L'interface IEnumerable définit une méthode GetEnumerator qui renvoie un objet qui implémente l' interface IEnumerator.
- Alors que l' interface IEnumerator définit des méthodes pour parcourir une séquence, telles que MoveNext et Current .
bande-annonce de fin
Dans le prochain article, étudions comment la boucle foreach traverse le conteneur