85 votes

Pourquoi IEnumerator of T hérite d'IDisposable, alors qu'un IEnumerator non générique n'en a PAS?

J'ai remarqué que le générique IEnumerator (of T) hérite d'IDisposable, mais que l'interface non générique IEnumerator n'en a PAS. Pourquoi est-il conçu de cette façon?

Habituellement, nous utilisons l'instruction foreach pour parcourir une instance IEnumerator (of T). Le code généré de foreach a en fait un bloc try-finally qui appelle Dispose () dans finally.

Edit: Mon esprit est un peu en désordre aujourd'hui. J'ai tapé IEnumerable en pensant à IEnumerator. L'ont changé.

93voto

Jon Skeet Points 692016

Fondamentalement, c'est un oubli. En C# 1.0, foreach jamais appelé Dispose 1. Avec C# 1.2 (présenté dans VS2003 - il n'y a pas de 1.1, bizarrement) foreach a commencé à vérifier dans l' finally bloc de si oui ou non l'itérateur mis en oeuvre IDisposable - qu'ils avaient à faire de cette façon, parce que rétrospectivement rendant IEnumerator étendre IDisposable aurait brisé tout le monde de la mise en œuvre de l' IEnumerator. Si ils avaient travaillé que c'est utile pour foreach à disposer d'itérateurs en premier lieu, j'en suis sûr, IEnumerator ont élargi IDisposable.

Quand C# 2.0 et .NET 2.0 est sorti, cependant, ils avaient une nouvelle occasion - une nouvelle interface, de nouveaux de succession. Il fait beaucoup plus de sens d'avoir l'interface étendre IDisposable , de sorte que vous n'avez pas besoin d'un temps d'exécution vérifier dans le bloc finally, et maintenant que le compilateur sait que si l'itérateur est un IEnumerator<T> il peut émettre un inconditionel de Dispose.

EDIT: C'est incroyablement utile pour Dispose d'être appelé à la fin de l'itération (mais il se termine). Il signifie que l'itérateur peut tenir à des ressources - qui rend possible pour elle, dire, lire un fichier ligne par ligne. Itérateur blocs générateur Dispose des implémentations qui assurez-vous que tout finally blocs le point en cours d'exécution" de l'itérateur sont exécutés lorsqu'il est éliminé - de sorte que vous pouvez écrire du code à l'intérieur de l'itérateur et le nettoyage doivent se produire de façon appropriée.


1 la Recherche de retour à l'1.0 spec, il a déjà été spécifié. Je n'ai pas encore été en mesure de vérifier cette déclaration plus tôt que la 1.0 mise en œuvre n'a pas d'appel Dispose.

6voto

Mark Cidade Points 53945

IEnumerable<T> ne pas hériter IDisposable. IEnumerator<T> n'héritent IDisposable cependant, alors que les non-générique IEnumerator ne l'est pas. Même lorsque vous utilisez foreach pour un non-générique IEnumerable (qui renvoie IEnumerator), le compilateur va générer un chèque de IDisposable et appelez dispose() si l'agent recenseur implémente l'interface.

Je suppose que pour le générique de l'agent Recenseur<T> hérite de IDisposable donc il n'a pas besoin d'être un moteur d'exécution de type check-qu'il peut tout simplement aller de l'avant et d'appeler dispose() qui devrait avoir de meilleures performances, car il peut être très probablement être optimisé à l'écart si l'agent recenseur a un vide méthode dispose ().

4voto

JAXN Points 11

Je sais que c'est un vieux débat, mais je reasontly a écrit une bibliothèque où j'ai utilisé IEnumerable de T/IEnumerator de T lorsque les utilisateurs de la bibliothèque pourrait implémenter des itérateurs ils devraient mettre en œuvre IEnumerator de T.

Je l'ai trouvé très étrange que IEnumerator de T pourrait hériter de IDisposable. Nous mettons en œuvre IDisposable si nous voulons gratuit unmanged ressources de droite? Donc, il ne serait pertinent que pour les agents recenseurs qui détiennent effectivement des ressources non managées comme un groupe ar etc. Pourquoi ne pas laisser les utilisateurs à mettre en œuvre à la fois IEnumerator de T et IDisposable sur leur énumérateur si ça a du sens? Dans mon livre, ce qui viole le principe de responsabilité unique - Pourquoi mélanger énumérateur de la logique et de la disposition des objets.

0voto

Aaron Powell Points 15598

IEnumerable` hérite-t-il de IDisposing? Selon le réflecteur .NET ou MSDN . Êtes-vous sûr de ne pas le confondre avec IEnumerator ? Cela utilise IDisposing car il ne sert qu’à énumérer une collection et non à la longévité.

0voto

Bevan Points 20976

Un peu dur d'être définitif sur cette question, sauf si vous parvenez à obtenir une réponse de AndersH lui-même, ou quelqu'un proche de lui.

Cependant, je pense qu'il se rapporte à la "rendement" mot-clé qui a été introduit en C# dans le même temps. Si vous regardez le code généré par le compilateur lors de la "yield return x" est utilisé, vous verrez la méthode enveloppé dans une classe helper qui implémente IEnumerator; avoir IEnumerator descendre de IDisposable assure qu'il peut nettoyer lorsque l'énumération est terminée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X