Why My Thread Safe Generic List Collection not Respect My Enumerator ??!!!

 Introduction


Enumerating through a collection is not a thread safe, Is it real ? this question is knocking my head since saw this subject in MSDN ( Link ) and subsequently more questions & ideas starts  in my mind. The real question was, why shall use thread safe collection? according to Microsoft, the answer was simple, it is for better and faster performance, however my understanding is also simple; all property and methods within the generic class shall be written using SyncLock, hope I'm correct, and here it is the code..

Public Class RiverNileList(Of T)
    Implements IList(Of T)

#Region " RiverNileList (of T) "

#Region " Field "

    Friend _lock As Object = CType(Nothing, Object)
    Friend _list As List(Of T) = CType(Nothing, List(Of T))

#End Region

#Region " Constructor "

    Public Sub New()
        Me.New(New Object)
    End Sub

    Friend Sub New(obj As Object)
        Me._lock = obj
    End Sub

#End Region

#Region " Property "

    Public ReadOnly Property InnerList As List(Of T)
        Get
            SyncLock Me._lock
                If Me._list Is Nothing Then
                    Me._list = New List(Of T)()
                End If
            End SyncLock
            Return Me._list
        End Get
    End Property

    Default Public Property Item(index As Integer) As T Implements IList(Of T).Item
        Get
            Dim value As T = CType(Nothing, T)
            SyncLock Me._lock
                value = Me.InnerList(index)
            End SyncLock
            Return value
        End Get
        Set(value As T)
            SyncLock Me._lock
                Me.InnerList(index) = value
            End SyncLock
        End Set
    End Property

    Public ReadOnly Property Count As Integer Implements ICollection(Of T).Count
        Get
            Dim value As Integer = CType(Nothing, Integer)
            SyncLock Me._lock
                value = Me.InnerList.Count
            End SyncLock
            Return value
        End Get
    End Property

    Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of T).IsReadOnly
        Get
            Dim value As Boolean = CType(Nothing, Boolean)
            SyncLock Me._lock
                value = False
            End SyncLock
            Return value
        End Get
    End Property

#End Region

#Region " Method "

    Public Function Where(predicate As Func(Of T, Boolean)) As RiverNileList(Of T)
        SyncLock Me._lock
            Return New RiverNileList(Of T)(CType(Me._list, IEnumerable(Of T)).Where(predicate).ToList())
        End SyncLock
    End Function

    Public Function FirstOrDefault(predicate As Func(Of T, Boolean)) As T
        SyncLock Me._lock
            Return CType(_list, IEnumerable(Of T)).FirstOrDefault(predicate)
        End SyncLock
    End Function

    Public Sub AddRange(collection As IEnumerable(Of T))
        SyncLock Me._lock
            Me.InnerList.AddRange(collection)
        End SyncLock
    End Sub

    Public Sub Add(item As T) Implements ICollection(Of T).Add
        SyncLock Me._lock
            Me.InnerList.Add(item)
        End SyncLock
    End Sub

    Public Sub Clear() Implements ICollection(Of T).Clear
        SyncLock Me._lock
            Me.InnerList.Clear()
        End SyncLock
    End Sub

    Public Function Contains(item As T) As Boolean Implements ICollection(Of T).Contains
        Dim value As Boolean = CType(Nothing, Boolean)
        SyncLock Me._lock
            value = Me.InnerList.Contains(item)
        End SyncLock
        Return value
    End Function

    Public Sub CopyTo(array() As T, arrayIndex As Integer) Implements ICollection(Of T).CopyTo
        SyncLock Me._lock
            Me.InnerList.CopyTo(array, arrayIndex)
        End SyncLock
    End Sub

    Public Sub CopyTo(array As T())
        SyncLock Me._lock
            Me.InnerList.CopyTo(array)
        End SyncLock
    End Sub

    Public Function Remove(item As T) As Boolean Implements ICollection(Of T).Remove
        Dim value As Boolean = CType(Nothing, Boolean)
        SyncLock Me._lock
            value = Me.InnerList.Remove(item)
        End SyncLock
        Return value
    End Function

    Public Function IndexOf(item As T) As Integer Implements IList(Of T).IndexOf
        Dim value As Integer = CType(Nothing, Integer)
        SyncLock Me._lock
            value = Me.InnerList.IndexOf(item)
        End SyncLock
        Return value
    End Function

    Public Sub Insert(index As Integer, item As T) Implements IList(Of T).Insert
        SyncLock Me._lock
            Me.InnerList.Insert(index, item)
        End SyncLock
    End Sub

    Public Sub RemoveAt(index As Integer) Implements IList(Of T).RemoveAt
        SyncLock Me._lock
            Me.InnerList.RemoveAt(index)
        End SyncLock
    End Sub

    Public Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator
        Dim value As IEnumerator(Of T) = CType(Nothing, IEnumerator(Of T))
        SyncLock Me._lock
            ' Why My collection not respect my Enumerator.......??????????????
            value = New RiverNileListEnumerator(Me)
            ' the collection works fine with this value
            'value = Me.InnerList.GetEnumerator()
        End SyncLock
        Return value
    End Function

    Private Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
        Dim value As IEnumerator = CType(Nothing, IEnumerator)
        SyncLock Me._lock
            value = New RiverNileListEnumerator(Me)
            'value = Me.InnerList.GetEnumerator()
        End SyncLock
        Return value
    End Function

#End Region

#End Region

#Region " Enumerator "

    Friend Class RiverNileListEnumerator
        Implements IEnumerator(Of T)

        Private _list As RiverNileList(Of T)
        Private _enumerator As IEnumerator(Of T)

        Public Sub New(list As RiverNileList(Of T))
            SyncLock Me._list._lock
                Me._list = New RiverNileList(Of T)()
                Me._list.AddRange(list)
                Me._enumerator = Me._list.InnerList.GetEnumerator()
            End SyncLock
        End Sub

        Public ReadOnly Property Current As T Implements IEnumerator(Of T).Current
            Get
                Dim value As T = CType(Nothing, T)
                SyncLock Me._list._lock
                    value = Me._enumerator.Current
                End SyncLock
                Return value
            End Get
        End Property

        Private ReadOnly Property Current1 As Object Implements IEnumerator.Current
            Get
                Dim value As Object = CType(Nothing, Object)
                SyncLock Me._list._lock
                    value = Me._enumerator.Current
                End SyncLock
                Return value
            End Get
        End Property

        Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
            Dim result As Boolean = CType(Nothing, Boolean)
            SyncLock Me._list._lock
                result = Me._enumerator.MoveNext()
            End SyncLock
            Return result
        End Function

        Public Sub Reset() Implements IEnumerator.Reset
            SyncLock Me._list._lock
                Me._enumerator.Reset()
            End SyncLock
        End Sub

        Public Sub Dispose() Implements IDisposable.Dispose
            SyncLock Me._list._lock
                Me._enumerator.Dispose()
            End SyncLock
        End Sub

    End Class

#End Region

End Class ' RiverNileList(Of T)

Points of Interest

while testing the collection, I found that it is return nothing, then in the GetEnumerator Method,  I made a small change  and replace my Enumerator with the InnerList Enumerator and then the collection works fine

to make the collection works for you, uncomment this line of code in the GetEnumerator Method.

value = Me.InnerList.GetEnumerator()


and comment this line of code in the same method

value = New RiverNileListEnumerator(Me)

 

In fact.....!!!!!!!!!!!!.......Just wonder

Why  my Thread Safe Generic Collection Not Respect my Enumerator??!!!


After searching and reading finally get the answer to my question and my collection works great:

For Each statement shall used as follows:

 Private Colors As RiverNileList(Of KnownColor) = New RiverNileList(Of KnownColor)() From {KnownColor.ActiveCaption, KnownColor.Aqua, KnownColor.YellowGreen}
 
        For Each clr As KnownColor In Colors.ToArray()
            ListBox2.Items.Add(clr)
        Next
 
 
To do this properly and to remove out the lock in the ToArray and Add methods
guess I shall to implement ICollection(OF T) 
instead of IList(OF T)which might be not support lock
 
 
 

Comments

Popular posts from this blog

مقدمة الي تشفير الحروف الأبجدية العربية

VB.NET Translucent Control using GDI+

Add Custom Event to a Class in VB.NET