| File: System\Xml\XPath\XPathNodeIterator.cs | Web Access |
| Project: src\runtime\src\libraries\System.Private.Xml\src\System.Private.Xml.csproj (System.Private.Xml) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Diagnostics; namespace System.Xml.XPath { [DebuggerDisplay("Position = {CurrentPosition}, Current = {debuggerDisplayProxy}")] public abstract class XPathNodeIterator : ICloneable, IEnumerable { internal int count = -1; object ICloneable.Clone() { return this.Clone(); } public abstract XPathNodeIterator Clone(); public abstract bool MoveNext(); public abstract XPathNavigator? Current { get; } public abstract int CurrentPosition { get; } public virtual int Count { get { if (count == -1) { XPathNodeIterator clone = this.Clone(); while (clone.MoveNext()) ; count = clone.CurrentPosition; } return count; } } public virtual IEnumerator GetEnumerator() { return new Enumerator(this); } private object? debuggerDisplayProxy { get { return Current == null ? null : (object)new XPathNavigator.DebuggerDisplayProxy(Current); } } /// <summary> /// Implementation of a resettable enumerator that is linked to the XPathNodeIterator used to create it. /// </summary> private sealed class Enumerator : IEnumerator { private readonly XPathNodeIterator _original; // Keep original XPathNodeIterator in case Reset() is called private XPathNodeIterator? _current; private bool _iterationStarted; public Enumerator(XPathNodeIterator original) { _original = original.Clone(); } public object Current { get { // 1. Do not reuse the XPathNavigator, as we do in XPathNodeIterator // 2. Throw exception if current position is before first node or after the last node if (_iterationStarted) { // Current is null if iterator is positioned after the last node if (_current == null) throw new InvalidOperationException(SR.Format(SR.Sch_EnumFinished, string.Empty)); Debug.Assert(_current.Current != null); return _current.Current.Clone(); } // User must call MoveNext before accessing Current property throw new InvalidOperationException(SR.Format(SR.Sch_EnumNotStarted, string.Empty)); } } public bool MoveNext() { // Delegate to XPathNodeIterator if (!_iterationStarted) { // Reset iteration to original position _current = _original.Clone(); _iterationStarted = true; } if (_current == null || !_current.MoveNext()) { // Iteration complete _current = null; return false; } return true; } public void Reset() { _iterationStarted = false; } } } }