منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب
تحقيق الواجهة IEnumerable(Of T) - نسخة قابلة للطباعة

+- منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب (http://vb4arb.com/vb)
+-- قسم : قسم لغة الفيجوال بيسك VB.NET (http://vb4arb.com/vb/forumdisplay.php?fid=182)
+--- قسم : قسم مقالات VB.NET (http://vb4arb.com/vb/forumdisplay.php?fid=184)
+--- الموضوع : تحقيق الواجهة IEnumerable(Of T) (/showthread.php?tid=4951)



تحقيق الواجهة IEnumerable(Of T) - RaggiTech - 03-10-12

كاتب الموضوع : samerselo

يتم تعريف الواجهة IEnumerable(T) بواسطة فئات تستطيع إعادة سلسلة من القيم بشكل متسلسل قيمة قيمة وتكمن الفائدة من إعادة البيانات بهذه الطريقة هي أنه لا يجب عليك تحميل مجموعة كاملة من البيانات في الذاكرة من أجل العمل عليها فأنت تستخدم ذاكرة كافية لتحميل عنصر واحد من البيانات ويمكن استخدام الفئات التي تحقق الواجهة IEnumerbale(T) مع حلقات For … Next أو مع استعلامات لينك Linq
فإن كان على تطبيق معين القراءة من ملف نصي كبير ويعيد أسطر الملف التي توافق معيار بحث معين فيستخدم التطبيق استعلامات لينك للعودة بالأسطر التي تطابق معيار بحث معين وللاستعلام عن محتويات الملف بواسطة استعلام لينك يجب على التطبيق تحميل محتويات الملف ضمن مصفوفة أو مجموعة ولكن عملية تحميل الملف بأكمله ضمن مصفوفة أو مجموعة تستهلك قدرا كبيرا من الذاكرة وبدلا عن ذلك يمكن لاستعلام لينك الاستعلام عن محتويات الملف باستخدام فئة قابلة للتعداد Enumerable Class تعيد فقط تلك القيم التي تطابق شرط البحث فالاستعلامات التي تعيد بضعة قيم مطابقة تستهلك قدرا أقل بكثير من الذاكرة
ويمكنك إنشاء فئة تحقق الواجهة IEnumerable(T) لتقدم البيانات المصدرية كبيانات قابلة للتعداد وفئتك التي تحقق الواجهة IEnumerable(T) ستحتاج إلى فئة ثانية تحقق الواجهة IEnumerator(T) للدوران حول البيانات المصدرية بحيث تمكنك هاتان الفئتان من إعادة عناصر البيانات بشكل متسلسل من نوع محدد وفي هذا المثال سنقوم بإنشاء فئتان الأولى تحقق الواجهة IEnumerbale(Of String) والثانية تحقق الواجهة IEnumerator(Of String) بحيث تستخدمان للقراءة من ملف نصي سطر واحد في كل مرة
أنشئ مشروعا جديدا من النوع Class Library وقم بتسميته StreamReaderEnumerable ثم من Solution Explorer قم بإعادة تسمية الملف Class1.vb إلى StreamReaderEnumerable.vb وإن سألتك بيئة التطوير اقبل تغيير اسم الفئة إلى StreamReaderEnumerable ثم انقر بزر الفأرة اليميني على المشروع StreamReaderEnumerable واختر Add ثم New item ثم Class وقم بتسمية الملف StreamReaderEnumerator.vb
افتح الملف StreamReaderEnumerable.vb وفي القسم العام بعد تعريف الفئة ادخل

كود :
Implements IEnumerable(Of String)
ثم اضغط Enter فيقوم فيجول بايزيك تلقائيا بإضافة العناصر الضرورية لتحقيق الواجهة IEnumerable(Of String) interface إلى كودك وسنقوم الآن بإضافة باني عام للفئة يأخذ محدد واحد هو مسار الملف

كود :
Private _filePath As String

Public Sub New(ByVal filePath As String)
_filePath = filePath
End Sub
سنقوم الآن بإضافة الكود المناسب للوظيفة GetEnumeratorبحيث تعيد تواجدا جديدا للفئة StreamReaderEnumerator ويمكن جعل تعريف هذه الوظيفة خاصا لأنك تريد عرض عناصر الواجهة IEnumerable(Of String) فقط اجعل كود الوظيفة مطابقا للتالي

كود :
Public Function GetEnumerator() _
As System.Collections.Generic.IEnumerator(Of String) _
Implements System.Collections.Generic.IEnumerable(Of String).GetEnumerator

Return New StreamReaderEnumerator(_filePath)
End Function

Public Function GetEnumerator1() _
As System.Collections.IEnumerator _
Implements System.Collections.IEnumerable.GetEnumerator

Return Me.GetEnumerator()
End Function
افتح الملف StreamReaderEnumerator.vb وفي القسم العام للفئة StreamReaderEnumerator أدخل السطر التالي ثم اضغط Enter

كود :
Implements IEnumerator(Of String)
فيتم إضافة العناصر الضرورية لتحقيق الواجهة IEnumerator(Of String) لكودك أضف الكود التالي الذي سيشكل باني الفئة التي ستقوم بفتح الملف وتنفيذ عمليات الدخل والخرج عليه بحيث يأخذ محددا وحيدا هو مسار الملف

كود :
Private _sr As IO.StreamReader

Public Sub New(ByVal filePath As String)
_sr = New IO.StreamReader(filePath)
End Sub
الخصائص الحالية لـلواجهات IEnumerator(Of String) و IEnumerator تعيد العنصر الحالي من الملف النصي كنص ويمكن جعل تعريف الخاصية Current خاصا لأنه عليك عرض خصائص الواجهة IEnumerable(Of String) فقط الآن اجعل كود الخاصية Current مطابقا للتالي

كود :
Private _current As String

Public ReadOnly Property Current() As String _
Implements IEnumerator(Of String).Current

Get
If _sr Is Nothing OrElse _current Is Nothing Then
Throw New InvalidOperationException()
End If

Return _current
End Get
End Property

Private ReadOnly Property Current1() As Object _
Implements IEnumerator.Current

Get
Return Me.Current
End Get
End Property
تتنقل الطريقة MoveNext للواجهة IEnumerator للعنصر التالي في الملف النصي وتحدث القيمة المعادة من الخاصية Current وإن لم يعد يوجد أية عناصر أخرى تعيد الطريقة MoveNext القيمة False وإلا فسوف تعيد القيمة True الآن اجعل كود MoveNext كما يلي

كود :
Public Function MoveNext() As Boolean _
Implements System.Collections.IEnumerator.MoveNext

_current = _sr.ReadLine()
If _current Is Nothing Then Return False
Return True
End Function
وتوجه الطريقة Reset للواجهة IEnumerator نقطة التكرار بالانتقال إلى نقطة البداية للملف النصي وتفرغ قيمة الخاصية CurrentItem
أجعل كود الطريقة Reset كما يلي

كود :
Public Sub Reset() _
Implements System.Collections.IEnumerator.Reset

_sr.DiscardBufferedData()
_sr.BaseStream.Seek(0, IO.SeekOrigin.Begin)
_current = Nothing
End Sub
وتضمن الطريقة Dispose للواجهة IEnumerator أن جميع المصادر الغير مدارة سيتم تحريرها قبل تدمير التكرار فمقبض الملف الذي يستخدم من قبل الغرض StreamReader هو موارد غير مدارة ويجب أن يتم إغلاقه قبل أن يتم تدمير تواجد التكرار استبدل الكود الذي ولد من أجل الطريقة Dispose بالكود التالي

كود :
Private disposedValue As Boolean = False

Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' Dispose of managed resources.
End If
_current = Nothing
_sr.Close()
_sr.Dispose()
End If

Me.disposedValue = True
End Sub

Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub

Protected Overrides Sub Finalize()
Dispose(False)
End Sub
من أجل تجربة الفئات التي قمنا بإنشائها قم بإضافة مشروع جديد من النوع Windows Application إلى Solution StreamReaderEnumerable ثم قم بإضافة مرجع لمكتبة الفئات StreamReaderEnumerable وذلك بالنقر بزر الفأرة الأيمن على المشروع الجديد ثم اختيار Add Reference ومن صفحة Projects اختر مكتبة الفئات المذكورة
أضف على النموذج ListBox و Button واجعل كود النموذج كما يلي

كود :
Imports StreamReaderEnumerable

Public Class Form1

Private Sub Button1_Click() Handles Button1.Click
Dim adminRequests = _
From line In New StreamReaderEnumerable.StreamReaderEnumerable("c:\ipconfig.txt") _
Where line.Contains("Display")

Me.ListBox1.Items.Clear()
Me.ListBox1.Items.AddRange(adminRequests.ToArray)
End Sub

End Class
حيث استخدمنا الفئة StreamReaderEnumerable في استعلام لينك يجلب السطور من الملف c:\ipconfig.txt التي تحتوي على الكلمة Display