/Rhino.Etl.Core/Enumerables/CachingEnumerable.cs

http://github.com/ayende/rhino-etl · C# · 132 lines · 60 code · 10 blank · 62 comment · 6 complexity · 18b1d03bc0b8117f86e80ffa11c93212 MD5 · raw file

  1. namespace Rhino.Etl.Core.Enumerables
  2. {
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. /// <summary>
  6. /// There are several places where we need to iterate over an enumerable
  7. /// several times, but we cannot assume that it is safe to do so.
  8. /// This class will allow to safely use an enumerable multiple times, by caching
  9. /// the results after the first iteration.
  10. /// </summary>
  11. /// <typeparam name="T"></typeparam>
  12. public class CachingEnumerable<T> : IEnumerable<T>, IEnumerator<T>
  13. {
  14. private bool? isFirstTime = null;
  15. private IEnumerator<T> internalEnumerator;
  16. private readonly LinkedList<T> cache = new LinkedList<T>();
  17. /// <summary>
  18. /// Initializes a new instance of the <see cref="CachingEnumerable&lt;T&gt;"/> class.
  19. /// </summary>
  20. /// <param name="inner">The inner.</param>
  21. public CachingEnumerable(IEnumerable<T> inner)
  22. {
  23. internalEnumerator = inner.GetEnumerator();
  24. }
  25. ///<summary>
  26. ///Returns an enumerator that iterates through the collection.
  27. ///</summary>
  28. ///
  29. ///<returns>
  30. ///A <see cref="T:System.Collections.Generic.IEnumerator`1"></see> that can be used to iterate through the collection.
  31. ///</returns>
  32. ///<filterpriority>1</filterpriority>
  33. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  34. {
  35. if(isFirstTime==null)
  36. {
  37. isFirstTime = true;
  38. }
  39. else if(isFirstTime.Value)
  40. {
  41. isFirstTime = false;
  42. internalEnumerator.Dispose();
  43. internalEnumerator = cache.GetEnumerator();
  44. }
  45. else
  46. {
  47. internalEnumerator = cache.GetEnumerator();
  48. }
  49. return this;
  50. }
  51. ///<summary>
  52. ///Returns an enumerator that iterates through a collection.
  53. ///</summary>
  54. ///
  55. ///<returns>
  56. ///An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.
  57. ///</returns>
  58. ///<filterpriority>2</filterpriority>
  59. public IEnumerator GetEnumerator()
  60. {
  61. return ((IEnumerable<T>)this).GetEnumerator();
  62. }
  63. ///<summary>
  64. ///Gets the element in the collection at the current position of the enumerator.
  65. ///</summary>
  66. ///
  67. ///<returns>
  68. ///The element in the collection at the current position of the enumerator.
  69. ///</returns>
  70. ///
  71. T IEnumerator<T>.Current
  72. {
  73. get { return internalEnumerator.Current; }
  74. }
  75. ///<summary>
  76. ///Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
  77. ///</summary>
  78. ///<filterpriority>2</filterpriority>
  79. public void Dispose()
  80. {
  81. internalEnumerator.Dispose();
  82. }
  83. ///<summary>
  84. ///Advances the enumerator to the next element of the collection.
  85. ///</summary>
  86. ///
  87. ///<returns>
  88. ///true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
  89. ///</returns>
  90. ///
  91. ///<exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
  92. public bool MoveNext()
  93. {
  94. bool result = internalEnumerator.MoveNext();
  95. if (result && isFirstTime.Value)
  96. cache.AddLast(internalEnumerator.Current);
  97. return result;
  98. }
  99. ///<summary>
  100. ///Sets the enumerator to its initial position, which is before the first element in the collection.
  101. ///</summary>
  102. ///
  103. ///<exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
  104. public void Reset()
  105. {
  106. internalEnumerator.Reset();
  107. }
  108. ///<summary>
  109. ///Gets the current element in the collection.
  110. ///</summary>
  111. ///
  112. ///<returns>
  113. ///The current element in the collection.
  114. ///</returns>
  115. ///
  116. ///<exception cref="T:System.InvalidOperationException">The enumerator is positioned before the first element of the collection or after the last element.-or- The collection was modified after the enumerator was created.</exception><filterpriority>2</filterpriority>
  117. public object Current
  118. {
  119. get { return internalEnumerator.Current; }
  120. }
  121. }
  122. }