10
votes

Pourquoi ne pas .NET a un énumérateur bidirectionnel?

On a posé quelques reprises à quelques reprises sur la manière dont vous pouvez mettre en œuvre un énumérateur bidirectionnel ( Ici , ici ). Ma question n'est pas comment em> (qui est triviale pour la plupart des cas), mais pourquoi em> aucun type de tel existe dans la plate-forme .NET.

public interface IBidirectionalEnumerator<T> : IEnumerator<T>
{
    bool MovePrev();
}


5 commentaires

Il y a quelque chose de très mal avec votre conception de collection si elle est énumérée dessus change son état.


D'accord. Mais il y a bien quelques collections qui devraient changer tout en énumérant, comme une collation ou une file d'attente.


Sauf si vous utilisez iEnumérable enveloppé sur un type de streaming ou une ressource système telle qu'un streamerrieur ou une liste de fichiers.


En outre, alors que toutes les collections sont des énumérations, toutes les énumérations ne sont pas des collections.


Convenu Matthew, mon commentaire était trop court. Les effets secondaires sont bien acceptables (les flux sont en effet un bon exemple et les requêtes sont une autre), mais elles doivent être localisées. Je pense que je suis enumérant sur quelque chose de plusieurs fois, même lors de la mise en marche entre les énumérateurs, devrait être cohérent. Sinon, vous faites des choses très inincutrices.


6 Réponses :


2
votes

Parce que personne n'a pensé à ce sujet, ou personne ne pensait que ce serait particulièrement utile ou parce qu'il n'y avait pas assez de budget ou ...

Ce n'est pas vraiment nécessaire, n'est-ce pas? Vous pouvez facilement le mettre en œuvre vous-même. Peut-être que l'équipe de BCL pensait que cela ne valait pas la peine de la mise en œuvre, des tests, de la documentation, etc. Ne sous-estimez jamais le coût d'une fonctionnalité, cela peut sembler "facile", mais il dispose de coûts.

particulièrement parce qu'une seule interface que personne implémente ne semblerait étrange, n'est-ce pas? Vous attendez-vous à la liste, au tableau, etc. Pour mettre en œuvre l'interface, qui est beaucoup de travail à la fin.


1 commentaires

Comme Raymond Chen dirait, toutes les fonctionnalités commencent avec -100 points.



1
votes

aussi, quelle serait la motivation pour cela? Prise en charge de la langue pour l'itération "en arrière"?

Le motif d'itérateur ne donne pas beaucoup de poids au concept de "directionnalité" d'un ensemble d'éléments. C'est un modèle simple pour fournir une interface simple pour itération sur un ensemble.


0 commentaires

3
votes
  • Ienumerator prend en charge la déclaration C # foreach ainsi que des constructions en boucle d'autres langues.
  • Il n'y a pas de déclaration ni d'idiome de programmation commune que Ibidirectionalenumerator permet.

6 commentaires

Ce n'est pas complètement vrai. C # nécessite uniquement la méthode MOVENNEXT et la propriété actuelle pour fonctionner. Il ne s'appuie pas sur l'interface du tout.


En fait, ienumerator n'est pas nécessaire pour foreach . Tant que votre classe a une méthode getenumerator () qui ne prend aucun paramètre et renvoie un objet qui a un objet actuel {obtenir; } Propriété et un VOID MOVENEXTEXT () méthode, puis foreach fonctionnera assez joyeusement avec elle.


Greg: vraiment ?! Donc, l'ienumerator est effectivement dactylographié? C'est une révélation.


Ce n'est pas typé de canard. C # Vérifiez simplement si le type implémente l'interface ou comporte les méthodes / propriétés nécessaires. L'IL produit pour une boucle de Foreach n'utilise pas iEnumerable nulle part, donc pas besoin de canard.


C'est ce que je voulais dire par dactylographie de canard. C'est le typing de canard de compilation, vrai, mais il s'agit toujours d'un canard.


Je pense que les itérateurs C ++ sont un idiome de programmation assez courant: cprogramming.com/taturial/stl/antitrant .html



4
votes

Lorsque vous concevez un cadre, vous devez prendre des décisions concernant de faire des choses à différents niveaux d'abstraction. Le compromis est que si vous choisissez d'exposer des éléments à un niveau d'abstraction élevé, vous obtiendrez une généralisation au coût de perte de contrôle grain fin. Si vous choisissez d'exposer des éléments à des niveaux d'abstraction inférieurs, votre concept ne peut pas également être généralisé, mais vous pouvez contrôler les détails à un niveau inférieur.

C'est une décision de conception. La mise en œuvre des deux sera coûteuse et créera un cadre plus gonflé et vous devrez prendre en charge les deux en ajoutant des fonctionnalités. Vous aurez besoin de préserver la compatibilité en arrière à l'avenir. Ce n'est pas une chose sage d'ajouter tout ce que vous pouvez penser à la BCL sans s'assurer qu'il a un avantage significatif.


0 commentaires

2
votes

Évidemment, il existe de nombreux types de collecte qui ne peuvent pas implémenter cela, car movenext () est destructeur ou modifie l'état de la collection sous-jacente.

movenext () n'est pas destructif. En fait, si l'état de la collection sous-jacente est modifié entre le moment où le ienumerator a été créé et l'heure movenext () est appelé, l'appel à MOVENNEXT () échouera.

Le but de ienumerator est de itérer sur tous les éléments d'une collection une fois, dans l'ordre natif de la collection si la collection a une ordonnance natale. ienumerator n'est pas conçu comme un périphérique de navigation de collecte, tel que celui que l'on pourrait trouver en C ++.


1 commentaires

Quel serait l'appareil de navigation de la collection C # alors? Je veux dire la version C # des itérateurs C ++?



1
votes

Une question plus grande est pourquoi .NET n'en mettant pas en œuvre IReaderByByIndex, qui serait à son tour hérité d'IList. Un tel type n'aurait rien ajouté au travail requis pour produire des implémentations ilistes en lecture-écriture et aurait réduit les travaux nécessaires pour produire des implémentations en lecture seule (qui mettront en place IReaderByByDex, plutôt qu'Ilist).

Ce n'est pas trop utile pour réfléchir à une telle "Pourquoi" s) cependant. .NET est ce que c'est. Le seul moyen de remédier à la situation de .NET 5.0 serait d'autoriser un moyen de déclarer qu'une interface qui implémente une propriété en lecture-écriture peut être réputée implémenter implicitement une version en lecture seule (afin de permettre à IList d'hériter un covariant IreadableByDex sans avoir à ajouter une méthode d'obtention explicite).


0 commentaires