تقييم الموضوع :
  • 1 أصوات - بمعدل 5
  • 1
  • 2
  • 3
  • 4
  • 5
[VB.NET] My ThreadSafe Generic IList Not Respect MyEnumerator
#1
مقدمـــــــــــــــــــــــــة

منذ يومان كنت أقرأ هذا الموضوع في MSDN ...اللينـــــــــــــــــــــــك

و هو يتحدث عن استخدام Thread -Safe من خلال Collection تحديدا.

و لتوضيح الأمر قليلا انه و علي ما يبدو أن Collection الموجودة في الدوت نت قد لا تسترجع القيم الموجودة بها بشكل دقيق من خلال جملة For Each

و تلك حالة نادرة جدا ربما لا تحدث علي الاطلاق و خصوصا عندما تكون Collection ليس بها متغيرات ضخمة أو لا تكون بها أعداد ضخمة جدا من المتغيرات

و كما اوضحت مايكروسوفت أن استخدام ThreadSafe Collection يساعد علي أداء و سرعة أفضل لهذا النوع من Collections

لذلك قررت أن أكتب Collection الخاصة بي لكي أطبق من خلالها نفس هذا الاسلوب الموجود في موضوع مايكروسوفت.

ربما بعض المبرمجين لا يحبذ أن يكتب مثل هذا النوع من الكود و يفضل أن يستخدم بدلا منها الكلاسات الموجودة بالفعل في الدوت نت

لكن و بالرغم انني أهتم فقط بالجرافكس لكن مفهومي للأمر بسيط تماما
و هو أن كتابة مثل هذا النوع من الكود يعتبر تجربة جيدة و فريدة جدا لتطوير أداء و قدرات أي مبرمج و بالتالي هذا يؤدي الي زيادة فهمه للأمور بشكل أفضل

في الواقع لقد قد كتبت الكثير مثل هذا النوع من الكود تحديدا و لقد قمت ببناء أكثر من Generic Collection

لكن في تلك المرة قررت أن أستخدم Generic IList و في واقع الأمر كانت تلك المرة الأولي لي التي فيها اقوم بعمل Implementation لهذا Interface

و بالفعل كتبت الكلاس و أيضا كتبت Enumerator الخاص به و الكود كاملا موجود أدناه

كود :
Public Class RiverNileThreadSafeList(Of T)
    Implements IList(Of T)

#Region " RiverNileThreadSafeList (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 Sub ForEach(action As Action(Of T))
        SyncLock Me._lock
            For Each item As Object In Me
                action(item)
            Next
        End SyncLock
    End Sub

    Public Function Where(predicate As Func(Of T, Boolean)) As RiverNileThreadSafeList(Of T)
        SyncLock Me._lock
            Return New RiverNileThreadSafeList(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

    Private Function CreateCairoEnumerator() As IEnumerator(Of T)
        Return New RiverNileThreadSafeListEnumerator(Me)
    End Function

    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 RiverNileThreadSafeListEnumerator(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 RiverNileThreadSafeListEnumerator(Me)
            'value = Me.InnerList.GetEnumerator()
        End SyncLock
        Return value
    End Function

#End Region

#End Region

#Region " My Enumerator "

    Friend Class RiverNileThreadSafeListEnumerator
        Implements IEnumerator(Of T)

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

        Public Sub New(list As RiverNileThreadSafeList(Of T))
            SyncLock Me._list._lock
                Me._list = New RiverNileThreadSafeList(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 ' RiverNileThreadSafeList(Of T)

ثم بعد ذلك قمت ب تجربة الكلاس الذي كتبته حتي أتأكد من أنه يعمل بصورة جيدة و هنا اكتشفت ان Collection الجديدة و بالرغم من أنها لا تعطي أي أخطاء علي الاظلاق عند استخدامها لكنها لا تسترجع أي قيمة بتاتا مع جملة For Each

كما هو واضح من الكود التالي

كود :
Public Class Test_Form

    Private ColorList As RiverNileThreadSafeList(Of KnownColor) = New RiverNileThreadSafeList(Of KnownColor)() From {KnownColor.ActiveCaption, KnownColor.Aqua, KnownColor.YellowGreen}

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' Test my collection with my Enumerator
        ' in this case no value will be add to the list box
        For Each clr As KnownColor In ColorList
            ListBox2.Items.Add(clr)
        Next
    End Sub
End Class


و راجعت الكود مرارا و تكرارا حتي أكتشف أين أخطات لكن بلا جدوي و لم أهتدي للمشكلة
و هنا أعدت كتابة الكلاس بشكل مختلف قليلا و قمت ب إلغاء Enumerator الذي كتبته و بدلا منه في جملة GetEnumerator استخدمت InnerList.GetEnumerator و هنا وجدت أن Collection تعمل بصورة جيدة واستطعت استرجاع جميع القيم منها بشكل طبيعي
و الكود التالي يوضخ شكل Collection بدون Enumerator الذي قمت أنا بكتابته

كود :
Public Class SafeListWithoutEnumerator(Of T)
    Implements IList(Of T)

#Region " SafeListWithoutEnumerator (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 Sub ForEach(action As Action(Of T))
        SyncLock Me._lock
            For Each item As Object In Me
                action(item)
            Next
        End SyncLock
    End Sub

    Public Function Where(predicate As Func(Of T, Boolean)) As SafeListWithoutEnumerator(Of T)
        SyncLock Me._lock
            Return New SafeListWithoutEnumerator(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
            ' 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 = Me.InnerList.GetEnumerator()
        End SyncLock
        Return value
    End Function

#End Region

#End Region

End Class ' SafeListWithoutEnumerator (of T)

و الكود التالي يوضح كيفية استخدامها


كود :
Public Class Test_Form
    Private KnownColorList As SafeListWithoutEnumerator(Of KnownColor) = New SafeListWithoutEnumerator(Of KnownColor)() From {KnownColor.Blue, KnownColor.ButtonFace, KnownColor.CadetBlue}
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' test colloection which has now written enumerator
        For Each item In KnownColorList
            ListBox1.Items.Add(item)
        Next
    End Sub
End Class

طبعا لم أقتنع بذلك لأنني أريد أن أفهم ما هي المشكلة في الكود الذي كتبته و أخذت أبحث هنا و هناك علي الانترنت حتي اهتديت الي الجواب بعد أن أضعت أكثر من حوالي ثلاثة ساعات أقرأ فيها كل ما هو له صلة بهذا الأمر

و الكود التالي يوضح كيفية استخدام Collection التي أنا كتبتها و بشكل صحيح

كود :
Public Class Test_Form

    Private ColorList As RiverNileThreadSafeList(Of KnownColor) = New RiverNileThreadSafeList(Of KnownColor)() From {KnownColor.ActiveCaption, KnownColor.Aqua, KnownColor.YellowGreen}
    Private KnownColorList As SafeListWithoutEnumerator(Of KnownColor) = New SafeListWithoutEnumerator(Of KnownColor)() From {KnownColor.Blue, KnownColor.ButtonFace, KnownColor.CadetBlue}

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' test colloection which has now written enumerator
        For Each item In KnownColorList
            ListBox1.Items.Add(item)
        Next

        ' the correct way to use my collection
        ' Test my collection with my Enumerator
        ' in this case values will be added to my Collectio

        For Each clr As KnownColor In ColorList.ToArray()
            ListBox2.Items.Add(clr)
        Next

    End Sub

End Class

الواضح هنا لي أنه علي ما يبدو أن Generic IList لا تدعم ThreadSafe و لذلك و من الافضل أن نستخدم بدلا منها Generic ICollection

هذا ما قرأته لكنني و حتي هذه اللحظة لم أتأكد من هذا الجواب 100%
لأنني في حاجة الي اعادة كتابة كل شئ باستخدام Generic ICollection بدلا من Generic IList

ربما أعيد كتابة Collection الخاصة بي مرة ثانية و أضع لكم الكود هنا لاحقا أو في المدونة الخاصة بي

أتمني أن يكون هذا الحوار البسيط مفيدا لكم

ستجدون الكود كاملا في المرفقات بنسخة الفيجوال استوديو 2012

تقبلوا تحياتي


الملفات المرفقة
.rar   test_ThreadSafeCollection.rar (الحجم : 82.45 ك ب / التحميلات : 13)
الرد }}}}
تم الشكر بواسطة: Sajad , الشاكي لله , سعود , Amir_alzubidy
#2
السلام عليكم

بارك الله فيكم

تحياتي
الرد }}}}
تم الشكر بواسطة:


المواضيع المحتمل أن تكون متشابهة .
الموضوع : الكاتب الردود : المشاهدات : آخر رد
  Generic Delegates & ًWindows Forms Control - Part 2 silverlight 0 197 19-01-16, 02:01 PM
آخر رد: silverlight
  [مقال] Generic Delegates - Func and Action silverlight 14 539 18-01-16, 12:57 AM
آخر رد: 10468
  Generic Delegates & ًWindows Forms Control - Part 1 silverlight 1 257 16-01-16, 06:35 PM
آخر رد: 10468

التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم