1+ // ***********************************************************************
2+ // Assembly : RzR.Shared.Extensions.DomainCommonExtensions
3+ // Author : RzR
4+ // Created On : 2026-01-28 22:01
5+ //
6+ // Last Modified By : RzR
7+ // Last Modified On : 2026-01-28 22:52
8+ // ***********************************************************************
9+ // <copyright file="ObservableEnumerator.cs" company="RzR SOFT & TECH">
10+ // Copyright © RzR. All rights reserved.
11+ // </copyright>
12+ //
13+ // <summary>
14+ // </summary>
15+ // ***********************************************************************
16+
17+ #region U S A G E S
18+
19+ using System ;
20+ using System . Collections ;
21+ using System . Collections . Generic ;
22+ using DomainCommonExtensions . CommonExtensions ;
23+
24+ // ReSharper disable PossibleMultipleEnumeration
25+
26+ #endregion
27+
28+ namespace DomainCommonExtensions . Collections
29+ {
30+ /// -------------------------------------------------------------------------------------------------
31+ /// <summary>
32+ /// An observable enumerator. This class cannot be inherited.
33+ /// </summary>
34+ /// <typeparam name="T">Generic type parameter.</typeparam>
35+ /// <seealso cref="T:System.Collections.Generic.IEnumerator{T}"/>
36+ /// =================================================================================================
37+ public sealed class ObservableEnumerator < T > : IEnumerator < T >
38+ {
39+ private readonly IEnumerable < T > _source ;
40+
41+ private T _current = default ;
42+ private T _peek = default ;
43+
44+ private bool _hasCurrent , _hasPeek ;
45+
46+ private IEnumerator < T > _inner ;
47+
48+ /// -------------------------------------------------------------------------------------------------
49+ /// <summary>
50+ /// Initializes a new instance of the <see cref="ObservableEnumerator{T}"/> class.
51+ /// </summary>
52+ /// <param name="source">The source data.</param>
53+ /// =================================================================================================
54+ internal ObservableEnumerator ( IEnumerable < T > source )
55+ {
56+ _source = source ;
57+ _inner = source . GetEnumerator ( ) ;
58+ }
59+
60+ /// -------------------------------------------------------------------------------------------------
61+ /// <summary>
62+ /// Initializes a new instance of the <see cref="ObservableEnumerator{T}"/> class.
63+ /// </summary>
64+ /// <param name="inner">The inner.</param>
65+ /// =================================================================================================
66+ internal ObservableEnumerator ( IEnumerator < T > inner )
67+ {
68+ _inner = inner ;
69+ }
70+
71+ /// -------------------------------------------------------------------------------------------------
72+ /// <summary>
73+ /// Gets a value indicating whether this object is last.
74+ /// </summary>
75+ /// <value>
76+ /// True if this object is last, false if not.
77+ /// </value>
78+ /// =================================================================================================
79+ public bool IsLast
80+ {
81+ get
82+ {
83+ EnsureStarted ( ) ;
84+ EnsurePeeked ( ) ;
85+
86+ return ! _hasPeek ;
87+ }
88+ }
89+
90+ /// <inheritdoc />
91+ public T Current
92+ {
93+ get
94+ {
95+ EnsureStarted ( ) ;
96+
97+ return _current ;
98+ }
99+ }
100+
101+ /// <inheritdoc />
102+ object IEnumerator . Current => Current ;
103+
104+ /// <inheritdoc />
105+ public bool MoveNext ( )
106+ {
107+ if ( _hasPeek )
108+ {
109+ _current = _peek ;
110+ _hasPeek = false ;
111+ _hasCurrent = true ;
112+
113+ return true ;
114+ }
115+
116+ if ( ! _inner . MoveNext ( ) )
117+ {
118+ _hasCurrent = false ;
119+
120+ return false ;
121+ }
122+
123+ _current = _inner . Current ;
124+ _hasCurrent = true ;
125+
126+ return true ;
127+ }
128+
129+ /// <inheritdoc />
130+ public void Reset ( )
131+ {
132+ if ( _source . IsNull ( ) )
133+ throw new NotSupportedException ( "Reset is not supported." ) ;
134+
135+ _inner . Dispose ( ) ;
136+ _inner = _source . GetEnumerator ( ) ;
137+
138+ _hasCurrent = false ;
139+ _hasPeek = false ;
140+ }
141+
142+ /// <inheritdoc />
143+ public void Dispose ( ) => _inner . Dispose ( ) ;
144+
145+ /// -------------------------------------------------------------------------------------------------
146+ /// <summary>
147+ /// Attempts to peek.
148+ /// </summary>
149+ /// <param name="value">[out] The value.</param>
150+ /// <returns>
151+ /// True if it succeeds, false if it fails.
152+ /// </returns>
153+ /// =================================================================================================
154+ public bool TryPeek ( out T value )
155+ {
156+ EnsureStarted ( ) ;
157+ EnsurePeeked ( ) ;
158+
159+ if ( _hasPeek )
160+ {
161+ value = _peek ;
162+
163+ return true ;
164+ }
165+
166+ value = default ;
167+
168+ return false ;
169+ }
170+
171+ /// -------------------------------------------------------------------------------------------------
172+ /// <summary>
173+ /// Ensures that peeked.
174+ /// </summary>
175+ /// =================================================================================================
176+ private void EnsurePeeked ( )
177+ {
178+ if ( _hasPeek )
179+ return ;
180+
181+ if ( _inner . MoveNext ( ) )
182+ {
183+ _peek = _inner . Current ;
184+ _hasPeek = true ;
185+ }
186+ }
187+
188+ /// -------------------------------------------------------------------------------------------------
189+ /// <summary>
190+ /// Ensures that enumeration started.
191+ /// </summary>
192+ /// <exception cref="InvalidOperationException">
193+ /// Thrown when the requested operation is invalid.
194+ /// </exception>
195+ /// =================================================================================================
196+ private void EnsureStarted ( )
197+ {
198+ if ( ! _hasCurrent )
199+ throw new InvalidOperationException ( "Enumeration has not started." ) ;
200+ }
201+ }
202+ }
0 commit comments