File: System\Collections\Immutable\DisposableEnumeratorAdapter_2.cs
Web Access
Project: src\src\libraries\System.Collections.Immutable\src\System.Collections.Immutable.csproj (System.Collections.Immutable)
// 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.Generic;
 
namespace System.Collections.Immutable
{
    /// <summary>
    /// An adapter that allows a single foreach loop in C# to avoid
    /// boxing an enumerator when possible, but fall back to boxing when necessary.
    /// </summary>
    /// <typeparam name="T">The type of value to be enumerated.</typeparam>
    /// <typeparam name="TEnumerator">The type of the enumerator struct.</typeparam>
    internal struct DisposableEnumeratorAdapter<T, TEnumerator> : IDisposable
        where TEnumerator : struct, IEnumerator<T>
    {
        /// <summary>
        /// The enumerator object to use if not null.
        /// </summary>
        private readonly IEnumerator<T>? _enumeratorObject;
 
        /// <summary>
        /// The enumerator struct to use if <see cref="_enumeratorObject"/> is <c>null</c>.
        /// </summary>
        /// <remarks>
        /// This field must NOT be readonly because the field's value is a struct and must be able to mutate
        /// in-place. A readonly keyword would cause any mutation to take place in a copy rather than the field.
        /// </remarks>
        private TEnumerator _enumeratorStruct;
 
        /// <summary>
        /// Initializes a new instance of the <see cref="DisposableEnumeratorAdapter{T, TEnumerator}"/> struct
        /// for enumerating over a strongly typed struct enumerator.
        /// </summary>
        /// <param name="enumerator">The initialized enumerator struct.</param>
        internal DisposableEnumeratorAdapter(TEnumerator enumerator)
        {
            _enumeratorStruct = enumerator;
            _enumeratorObject = null;
        }
 
        /// <summary>
        /// Initializes a new instance of the <see cref="DisposableEnumeratorAdapter{T, TEnumerator}"/> struct
        /// for enumerating over a (boxed) <see cref="IEnumerable{T}"/> enumerator.
        /// </summary>
        /// <param name="enumerator">The initialized enumerator object.</param>
        internal DisposableEnumeratorAdapter(IEnumerator<T> enumerator)
        {
            _enumeratorStruct = default(TEnumerator);
            _enumeratorObject = enumerator;
        }
 
        /// <summary>
        /// Gets the current enumerated value.
        /// </summary>
        public T Current
        {
            get { return _enumeratorObject != null ? _enumeratorObject.Current : _enumeratorStruct.Current; }
        }
 
        /// <summary>
        /// Moves to the next value.
        /// </summary>
        public bool MoveNext()
        {
            return _enumeratorObject != null ? _enumeratorObject.MoveNext() : _enumeratorStruct.MoveNext();
        }
 
        /// <summary>
        /// Disposes the underlying enumerator.
        /// </summary>
        public void Dispose()
        {
            if (_enumeratorObject != null)
            {
                _enumeratorObject.Dispose();
            }
            else
            {
                _enumeratorStruct.Dispose();
            }
        }
 
        /// <summary>
        /// Returns a copy of this struct.
        /// </summary>
        /// <remarks>
        /// This member is here so that it can be used in C# foreach loops.
        /// </remarks>
        public DisposableEnumeratorAdapter<T, TEnumerator> GetEnumerator()
        {
            return this;
        }
    }
}