Synchronised Dictionary

In .NET 2.0 and above the SyncRoot was removed from the Dictionary and Hastable classes which meant you can't create thread-safe versions of these anymore. This was done (properly in my reasoning) by the .NET team to move synchronisation to be the responsibility of the developer as synchronisation usually happens at a higher level and could involve multiple resources which needed to be synchronised together.

Now saying all that, there are places where a simple thread safe dictionary or list class is just a necessity
and it's a complete pain having to develop your our synchronisation around it each time.

So here I provide a simple implementation of a generic synchronised dictionary class that is thread-safe, this was developed in .NET 3.5 using the new Threading.ReaderWriterLockSlim class.

Public Class SynchronisedDictionary(Of KEY_TYPE, ITEM_TYPE)
    Implements IDictionary(Of KEY_TYPE, ITEM_TYPE)
    Private _rwLock As New Threading.ReaderWriterLockSlim
    Private _dict As New Generic.Dictionary(Of KEY_TYPE, ITEM_TYPE)

    Private Class AcquireWriteLock
        Implements IDisposable
        Private _rwLock As New Threading.ReaderWriterLockSlim
        Public Sub New(ByVal rwLock As Threading.ReaderWriterLockSlim)
            _rwLock = rwLock
            _rwLock.EnterWriteLock()
        End Sub
        Private disposedValue As Boolean = False        ' To detect redundant calls

        ' IDisposable
        Protected Overridable Sub Dispose(ByVal disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    ' TODO: free other state (managed objects).
                    _rwLock.ExitWriteLock()
                End If
                ' TODO: free your own state (unmanaged objects).
                ' TODO: set large fields to null.
            End If
            Me.disposedValue = True
        End Sub
#Region " IDisposable Support "
        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region
    End Class
    Private Class AcquireReadLock
        Implements IDisposable
        Private _rwLock As New Threading.ReaderWriterLockSlim
        Public Sub New(ByVal rwLock As Threading.ReaderWriterLockSlim)
            _rwLock = rwLock
            _rwLock.EnterReadLock()
        End Sub
        Private disposedValue As Boolean = False        ' To detect redundant calls

        ' IDisposable
        Protected Overridable Sub Dispose(ByVal disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    ' TODO: free other state (managed objects).
                    _rwLock.ExitReadLock()
                End If
                ' TODO: free your own state (unmanaged objects).
                ' TODO: set large fields to null.
            End If
            Me.disposedValue = True
        End Sub
#Region " IDisposable Support "
        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region
    End Class
    Public Sub Add(ByVal item As System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)) Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).Add
        Using New AcquireWriteLock(_rwLock)
            _dict(item.Key) = item.Value
        End Using
    End Sub
    Public Sub Clear() Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).Clear
        Using New AcquireWriteLock(_rwLock)
            _dict.Clear()
        End Using
    End Sub
    Public Function Contains(ByVal item As System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)) As Boolean Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).Contains
        Using New AcquireReadLock(_rwLock)
            Return _dict.Contains(item)
        End Using
    End Function

    Public Sub CopyTo(ByVal array() As System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE), ByVal arrayIndex As Integer) Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).CopyTo
        Using New AcquireReadLock(_rwLock)
            _dict.ToArray.CopyTo(array, arrayIndex)
        End Using
    End Sub

    Public ReadOnly Property Count() As Integer Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).Count
        Get
            Using New AcquireReadLock(_rwLock)
                Return _dict.Count
            End Using
        End Get
    End Property
    Public ReadOnly Property IsReadOnly() As Boolean Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).IsReadOnly
        Get
            Return False
        End Get
    End Property
    Public Function Remove(ByVal item As System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)) As Boolean Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).Remove
        Using New AcquireWriteLock(_rwLock)
            Return _dict.Remove(item.Key)
        End Using
    End Function

    Public Sub Add(ByVal key As KEY_TYPE, ByVal value As ITEM_TYPE) Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).Add
        Using New AcquireWriteLock(_rwLock)
            _dict(key) = value
        End Using
    End Sub

    Public Function ContainsKey(ByVal key As KEY_TYPE) As Boolean Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).ContainsKey
        Using New AcquireReadLock(_rwLock)
            Return _dict.ContainsKey(key)
        End Using
    End Function
    Default Public Property Item(ByVal key As KEY_TYPE) As ITEM_TYPE Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).Item
        Get
            Using New AcquireReadLock(_rwLock)
                Return _dict(key)
            End Using
        End Get
        Set(ByVal value As ITEM_TYPE)
            Using New AcquireWriteLock(_rwLock)
                _dict(key) = value
            End Using
        End Set
    End Property
    Public ReadOnly Property Keys() As System.Collections.Generic.ICollection(Of KEY_TYPE) Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).Keys
        Get
            Using New AcquireReadLock(_rwLock)
                Return _dict.Keys
            End Using
        End Get
    End Property
    Public Function Remove(ByVal key As KEY_TYPE) As Boolean Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).Remove
        Using New AcquireWriteLock(_rwLock)
            _dict.Remove(key)
        End Using
    End Function

    Public Function TryGetValue(ByVal key As KEY_TYPE, ByRef value As ITEM_TYPE) As Boolean Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).TryGetValue
        Using New AcquireReadLock(_rwLock)
            Return _dict.TryGetValue(key, value)
        End Using
    End Function

    Public ReadOnly Property Values() As System.Collections.Generic.ICollection(Of ITEM_TYPE) Implements System.Collections.Generic.IDictionary(Of KEY_TYPE, ITEM_TYPE).Values
        Get
            Using New AcquireReadLock(_rwLock)
                Return _dict.Values
            End Using
        End Get
    End Property
    Public Function GetEnumeratorGeneric() As System.Collections.Generic.IEnumerator(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)) Implements System.Collections.Generic.IEnumerable(Of System.Collections.Generic.KeyValuePair(Of KEY_TYPE, ITEM_TYPE)).GetEnumerator
        Using New AcquireReadLock(_rwLock)
            Return _dict.GetEnumerator
        End Using
    End Function
    Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Using New AcquireReadLock(_rwLock)
            Return _dict.GetEnumerator
        End Using
    End Function
End Class