File: FrameworkFork\Microsoft.Xml\Xml\XPath\XPathNodeIterator.cs
Web Access
Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections;
using System.Diagnostics;
using System.Text;
 
namespace Microsoft.Xml.XPath
{
    using System;
    using Microsoft.Xml;
 
 
    [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 resetable enumerator that is linked to the XPathNodeIterator used to create it.
        /// </summary>
        private class Enumerator : IEnumerator
        {
            private XPathNodeIterator _original;     // Keep original XPathNodeIterator in case Reset() is called
            private XPathNodeIterator _current;
            private bool _iterationStarted;
 
            public Enumerator(XPathNodeIterator original)
            {
                _original = original.Clone();
            }
 
            public virtual 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(string.Format(ResXml.Sch_EnumFinished, string.Empty));
 
                        return _current.Current.Clone();
                    }
 
                    // User must call MoveNext before accessing Current property
                    throw new InvalidOperationException(string.Format(ResXml.Sch_EnumNotStarted, string.Empty));
                }
            }
 
            public virtual 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 virtual void Reset()
            {
                _iterationStarted = false;
            }
        }
 
        private struct DebuggerDisplayProxy
        {
            private XPathNodeIterator _nodeIterator;
 
            public DebuggerDisplayProxy(XPathNodeIterator nodeIterator)
            {
                _nodeIterator = nodeIterator;
            }
 
            public override string ToString()
            {
                // Position={CurrentPosition}, Current={Current == null ? null : (object) new XPathNavigator.DebuggerDisplayProxy(Current)}
                StringBuilder sb = new StringBuilder();
                sb.Append("Position=");
                sb.Append(_nodeIterator.CurrentPosition);
                sb.Append(", Current=");
                if (_nodeIterator.Current == null)
                {
                    sb.Append("null");
                }
                else
                {
                    sb.Append('{');
                    sb.Append(new XPathNavigator.DebuggerDisplayProxy(_nodeIterator.Current).ToString());
                    sb.Append('}');
                }
                return sb.ToString();
            }
        }
    }
}