2010-04-26 6 views
5

Je porte une bibliothèque de C++ à C#. L'ancienne bibliothèque utilise des vecteurs de C++ et dans le C# j'utilise des dictionnaires génériques parce qu'ils sont en fait une bonne structure de données pour ce que je fais (chaque élément a un ID, puis je l'utilise en utilisant TypeDictionary = Dictionary<String, Type>;). Maintenant, dans le code C# J'utilise une boucle comme celui-ciComment savoir si un énumérateur a atteint la fin de la collection en C#?

TypeDictionary.Enumerator tdEnum = MyTypeDictionary.GetEnumerator(); 

while(tdEnum.MoveNext()) 
{ 
    Type element = typeElement.Current.Value; 

    // More code here 
} 

à itérer les éléments de la collection. Le problème est que dans des cas particuliers, je dois vérifier si un certain recenseur a atteint la fin de la collection, en C++ je l'aurais fait un chèque comme celui-ci:

if (tdEnum == MyTypeDictionary.end()) // More code here 

Mais je ne sais pas comment gérer cette situation en C#, des idées?

Merci
Tommaso

Répondre

3

Vous savez que vous êtes à la fin d'un itérateur quand MoveNext() retours false. Sinon, vous devez passer à une structure de données plus descriptive, telle que IList<T>.

4

J'ai une classe "smart iterator" dans MiscUtil que vous pouvez trouver utile. Il vous permet de tester si vous regardez actuellement le début ou la fin de la séquence, et l'index dans la séquence. Voir le usage page pour plus d'informations.

Bien sûr, dans la plupart des cas, vous pouvez simplement faire cela manuellement en utilisant le résultat de MoveNext(), mais parfois l'encapsulation supplémentaire est pratique.

Notez que, par nécessité, cet itérateur aura toujours consommé une valeur de plus que ce qu'il a donné, afin de savoir s'il a atteint ou non la fin. Dans la plupart des cas, ce n'est pas un problème, mais il peut occasionnellement donner des expériences bizarres lors du débogage.

+0

Merci pour votre bibliothèque, je bookmarked, mais pour cette fois, je vais juste aller avec la solution rapide. :) – tunnuz

1

En venant de C++, vous pourriez ne pas être à jour sur la syntaxe C#. Peut-être pourriez-vous simplement utiliser la construction foreach pour éviter le test tous ensemble. Le code suivant sera exécuté une fois pour chaque élément dans votre dictionnaire:

foreach (var element in MyTypeDictionary) 
{ 
    // More code here 
} 
2

En utilisant le modèle de décorateur pour tenir une valeur si le recenseur a pris fin est une approche valable. Puisqu'il implémente IEnumerator, vous ne trouverez pas de difficultés pour le remplacer dans votre code.

est ici une classe de test:

using System.Collections.Generic; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 
using MyDictionary = System.Collections.Generic.Dictionary<int, string>; 
using MyKeyValue = System.Collections.Generic.KeyValuePair<int, string>; 

namespace TestEnumerator 
{ 
    [TestClass] 
    public class UnitTest1 
    { 
     [TestMethod] 
     public void TestingMyEnumeradorPlus() 
     { 
      var itens = new MyDictionary() 
      { 
       { 1, "aaa" }, 
       { 2, "bbb" } 
      }; 
      var enumerator = new EnumeradorPlus<MyKeyValue>(itens.GetEnumerator()); 
      enumerator.MoveNext(); 
      Assert.IsFalse(enumerator.Ended); 
      enumerator.MoveNext(); 
      Assert.IsFalse(enumerator.Ended); 
      enumerator.MoveNext(); 
      Assert.IsTrue(enumerator.Ended); 
     } 
    } 

    public class EnumeradorPlus<T> : IEnumerator<T> 
    { 
     private IEnumerator<T> _internal; 
     private bool _hasEnded = false; 

     public EnumeradorPlus(IEnumerator<T> enumerator) 
     { 
      _internal = enumerator; 
     } 

     public T Current 
     { 
      get { return _internal.Current; } 
     } 

     public void Dispose() 
     { 
      _internal.Dispose(); 
     } 

     object System.Collections.IEnumerator.Current 
     { 
      get { return _internal.Current; } 
     } 

     public bool MoveNext() 
     { 
      bool moved = _internal.MoveNext(); 
      if (!moved) 
       _hasEnded = true; 
      return moved; 
     } 

     public void Reset() 
     { 
      _internal.Reset(); 
      _hasEnded = false; 
     } 

     public bool Ended 
     { 
      get { return _hasEnded; } 
     } 
    } 
} 
+0

Enumera ** d ** ou? faute de frappe? Devrait être Enumera ** t ** ou – IlPADlI

+1

Oui, étant donné que l'exemple a été écrit en anglais, c'est une faute de frappe (bien que dans ma langue maternelle c'est le mot «énumérateur»). Cependant, c'est le nom de la classe, donc cela n'affecte pas le résultat. – Fabio

Questions connexes