Synchronized IEnumerator <T>

I am building my own SynchronizedCollection<T>class to have a synchronized Observable collection for my WPF application. Synchronization is provided through ReaderWriterLockSlim, which for the most part was easy to use. The case I came across is how to provide a thread safe collection enumeration. I created my own IEnumerator<T>nested class that looks like this:

    private class SynchronizedEnumerator : IEnumerator<T>
    {
        private SynchronizedCollection<T> _collection;
        private int _currentIndex;

        internal SynchronizedEnumerator(SynchronizedCollection<T> collection)
        {
            _collection = collection;
            _collection._lock.EnterReadLock();
            _currentIndex = -1;
        }

        #region IEnumerator<T> Members

        public T Current { get; private set;}

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            var collection = _collection;
            if (collection != null)
                collection._lock.ExitReadLock();

            _collection = null;
        }

        #endregion

        #region IEnumerator Members

        object System.Collections.IEnumerator.Current
        {
            get { return Current; }
        }

        public bool MoveNext()
        {
            var collection = _collection;
            if (collection == null)
                throw new ObjectDisposedException("SynchronizedEnumerator");

            _currentIndex++;
            if (_currentIndex >= collection.Count)
            {
                Current = default(T);
                return false;
            }

            Current = collection[_currentIndex];
            return true;
        }

        public void Reset()
        {
            if (_collection == null)
                throw new ObjectDisposedException("SynchronizedEnumerator");

            _currentIndex = -1;
            Current = default(T);
        }

        #endregion
    }

, , , Enumerator Dispose, . , foreach Dispose. , , Enumerator. caveat, Dispose Enumerator ? , , , , .


( ), , . , , , . - , .

+3
4

, . , . . , foreach, MoveNext/Current , .

, . Microsoft , .NET 1.x. , , , GetEnumerator(). , , .

+3

. , / , , , .

- IEnumerable<T>, , , - , .

, , . , . , .

, , IEnumerable<T>, :

public class SomeCollection<T>
{
    // ...

    public void EnumerateInLock(Action<IEnumerable<T>> action) ...

    // ...
}

, , :

someCollection.EnumerateInLock(e =>
    {
        foreach (var item in e)
        {
            // blah
        }
    });

( , lock) , . .

EnumerateInLock :

public void EnumerateInLock(Action<IEnumerable<T>> action)
{
    var e = new EnumeratorImpl(this);

    try
    {
        _lock.EnterReadLock();
        action(e);
    }
    finally
    {
        e.Dispose();
        _lock.ExitReadLock();
    }
}

, EnumeratorImpl ( ) . ObjectDisposedException ( Dispose, .)

, :

IEnumerable<C> keepForLater = null;
someCollection.EnumerateInLock(e => keepForLater = e);

foreach (var item in keepForLater)
{
    // aha!
}

, , .

, , , Lisp , , IDisposable, : , " ".

, , , , , , , .. IEnumerable<T> . , ? , .

- . , . , . , , , .

( ) , : , , -; . , - ( ), , . , ( ) "" , , - ? , , ... . !

" " , , , , , , , . ! , , , , , .

, , , , , .

+2

IDisposable Dispose(bool managed), , . Dispose(false) , , . , Dispose(true), true , . , public Dispose() , Dispose(true), GC.SuppressFinalize(this), ( ).

, , , , . , , using(){ ... }, .

+1

. , , - , (), / count ( GetEnumerator(), -, :

public IEnumerator<T> GetEnumerator() { return inner.GetEnumerator();}

Addetc. need to synchronize, but they change the link inner(since the reference updates are atomic, you do not need to synchronize GetEnumerator()). This means that any enumerator will return as many elements as there were when the counter was created.

Of course, it helps that my script is simple, and my list was Addonly ... if you need to support mutate / remove, it is much more complicated.

+1
source

Source: https://habr.com/ru/post/1740664/


All Articles