Notes d'étude C # - Comprendre IEnumerable et IEnumerator de peu profond à profond

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);
        }
    }
}

insérez la description de l'image ici
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
insérez la description de l'image ici
lorsque nous appelons MoveNext . C'est-à-dire que l'index pointe vers 0, à ce moment le Current est 1
insérez la description de l'image ici
et ensuite MoveNext est appelé tout le temps ...

Lorsque index = 2 , c'est-à-dire pointant vers l'élément 3
insérez la description de l'image ici

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

Je suppose que tu aimes

Origine blog.csdn.net/qq_52855744/article/details/130601250
conseillé
Classement