مفهوم Generics بشكل مبسط
بسم الله الرحمن الرحيم , و السلام عليكم و رحمة الله و بركاته.
اطرح هذا الموضوع لكشف الغطاء عن مفهوم Generics بشكل مبسط وبعيداً عن التعقيد , أي مجرد افكار بسيطة ليتم استيعابها من الذين لم يستوعبوها.
الفكرة من هذا المفهوم بأبسط تفسيراتها جاءت من مفهوم اعادة تحميل الدالة بشكل زائد او ما يسمى (OverLoading).(اعادة تعريف ,اعادة قيادة)
فمثلاً لو كان لديك دالة تقوم بعرض رسالة و هذه الدالة تأخذ وسيطة نصية (نص الرسالة)و من ثم تقوم بعرضها.
مثال1:
PHP كود :
Public Shared Sub ShowMsg(ByVal x As String)
MsgBox(x)
End Sub
و اردت ان تجعل الدالة اكثر تعميما بحيث ان تكون الوسيطة هذه المرة رقمية,و في مرة اخرى نوع اخر ,هذا ما يسمى بإعادة القيادة.
PHP كود :
Public Shared Sub ShowMsg(ByVal x As Integer)
MsgBox(x)
End Sub
Public Shared Sub ShowMsg(ByVal x As Long)
MsgBox(x)
End Sub
لاحظ عند استدعائك للدالة ستتوفر لديك 3 نسخ محملة بشكل متتالي كل واحدة لها نوع من البيانات.
انا استخدمت هذه الدالة بشكلها المبسط للتسهيل فقط , اذ ان عرض رسالة لا يحتاج لمثل هذا التعقيد , ولكن للتوضيح فقط...؟
الان ماذا لو اردت ان توسع الدالة لتقوم بعرض انواع اضافية غير الانواع السابقة ,اكيد ستكتب دالة جديدة فيها النوع الجديد ,و ماذا لو استمرت الحاجة الى انواع جديدة..؟
اذاً انت محتاج الى حل يمكنك من استخدامها مع أي نوع تريد من دون الدخول و اضافة دوال جديدة كل مرة.
لهذا جاء مفهوم الــ Generics ليريحك من هذا العناء.يخبرك الـ Generic انه بإمكانك ان تعرف دالة تأخذ وسائط مجهولة النوع و من ثم عن استدعائك لها تعوض النوع في مكان المجاهيل و تنتهي المشكلة...؟
شكل الدالة
PHP كود :
Public Shared Sub ShowMsg(Of T)(ByVal x As T)
MsgBox(x)
End Sub
و شرحها بكل بساطة :المتغيرات ستكون من النوع T المجهول , و عند حاجتي لاستدعائها ساضع مكان T الاولى النوع ومن ثم مكان T الثانية قيمة النوع, فلو اردت ان اعرض ارقام من النوع Integer ستصبح الدالةعند الاستدعاء:
PHP كود :
ShowMsg(Of Integer)(25215)
سهلة و مريحة و وفرت علي الكثير من الوقت.
لم ينتهي الكلام هنا , اذ ان مفهوم Generics يمكن تطبيقه على الكلاسات و التراكيب ايضاً
بنفس الطريقة تماما , و ممكن ان تكون الحقول داخلها من النوع T و كذلك الدوال و الخصائص.
مفهوم Generic Collection
هذا المفهوم يمكن شرحه كالتالي:
تخيل ان لديك اكثر من كلاس و كل كلاس يخص جدول محدد و كل الكلاسات هذه تشترك في نوع معين من الوظائف مثل (الاضافة و الحذف و التعديل و البحث... و غيرها),فبدل ان تكتب وظائف لكل كلاس على حدا , (مثل كلاس الطلاب ,و كلاس الموظفين,و كلاس العملاء..الخ)
هنا جاء Generic Collection كحل لهذا الموضوع فكما سبق كل ما عليك هو الاعتماد على الانواع المجهولة و عند الحاجة للاستدعاء تغير المجهول بنوع البيانات الذي تريد التعامل معه.
انظر لهذا Collection
PHP كود :
Public Class My_Collection(Of T)
Private List As New List(Of T)()
Public Function GetItem(ByVal i As Integer) As T
Return List(i)
End Function
Public Sub InsertItem(ByVal p As T)
List.Add(p)
End Sub
Public Sub ClearList()
List.Clear()
End Sub
Public Function GetCount()
Return List.Count
End Function
Public Sub InsertAt(ByVal index As Integer, ByVal item As T)
List.Insert(index, item)
End Sub
Public Function Contains(ByVal item As T) As Boolean
Return List.Contains(item)
End Function
Public Function IndexOf(ByVal item As T) As Integer
Return List.IndexOf(item)
End Function
Public Sub Remove(ByVal item As T)
List.Remove(item)
End Sub
End Class
فهو يستقبل أي كلاس و يمكنك الاستفادة من وظائفه المجهولة و غير المجهولة لتطبيق العمليات على الكلاس المراد تمريره
سأفرض ان لدي جدول للعملاء و يحتوي على حقلين المعرف و الاسم.
سأعرف كلاس موافق له يحتوي على الحقلين السابقين و سأعرف له Constructor.
بنية الكلاس :
PHP كود :
Public Class Customer
Public Sub New(_id As Integer, _name As String)
ID = _id
Name = _name
End Sub
Private m_id As Integer
Public Property ID() As Integer
Get
Return m_id
End Get
Set
m_id = Value
End Set
End Property
Private m_name As String
Public Property Name() As String
Get
Return m_name
End Get
Set
m_name = Value
End Set
End Property
End Class
الان و وفق الكلاس السابق يمكنني انشاء عملاء جدد:
PHP كود :
Dim Fesal As New Customer(1, "fesal")
و بالاستفادة من Collection السابق لدي وظائف جاهزة فقط امرر الكلاس كوسيطة و استفيد من الوظائف.
PHP كود :
Dim Fesal As New Customer(1, "fesal")
Dim Nader As New Customer(2, "nader")
Dim Sosan As New Customer(3, "sosan")
Dim CustCollection As New My_Collection(Of Customer)()
CustCollection.InsertItem(Fesal)
CustCollection.InsertItem(Nader)
CustCollection.InsertAt(2,Sosan)
MsgBox(CustCollection.Contains(Fesal))
هل اتضحت لديك الصور الان...
مفهوم T As
يقابلها في C# مفهوم T Where
من اسمه هو شرط للعناصر التي من النوع T ,بمعنى اخر لا تقبل سوى الانواع التي تأتي بعد كلمة Where او As مثل ان تكون الانواع مثل Class,Integer... او أي نوع يأتي بعد الحرف T مقبولة في التعامل و بمعنى ابسط يمكن تمرير الانواع السابقة كوسائط للـ Collection فقط
مثال1:
where T : class
من النوع RefernceType
ــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــ
Where T :Struct
من النوع ValueTpe
ـــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــ
Where T : New
يجب ان يحتوي على Constructor
____________________________________________
Where T :ClassName
يجب ان يكون مشتق من كلاس اخر
____________________________________________Where T :InterFaceName
يجب ان يطبق أي InterFace
___________________________________________________
و بالتطبيق على Collection السابق لدينا ليقبل فقط Class مع Constructor .
سنكتبه كما يلي :
PHP كود :
Public Class My_Collection(Of T As {Class, New})
PHP كود :
public class My_Collection <T> where T : class, new()
و اخيراً يبقى سؤال ...؟
هل تقبل الـ Collection اكثر من وسيطة مجهول وهل استطيع ان احدد الانواع لكل وسيطة.
نعم تستطيع ذلك و بكل سهولة كما تعمل مع أي دالة تستقبل وسائط..
مثال:
PHP كود :
Public Class My_Collection2(Of T As {Class, New}, K As {Structure})
End Class
و مع Generic ايضاً
مثال مع اجراء:
PHP كود :
Private Sub TransFer(Of T)(data As List(Of T), X As Integer)
End Sub
Private Sub Export(Of T)(data As List(Of T), ParamArray parameters As String())
End Sub
كما ترى الوسيطة الاولى مجهولة و الثانية معلومة النوع.
ان شاء الله تكون الامور تكشفت عن مفهوم Generics ولو بشكل بسيط , و الله الموفق.
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال