Dim X As New TestClass
X.TestProperty = 100
المشكلة ان VB6 يطبق ما يسمى التقليد الأعمى، حيث ان الخاصية TestProperty السابقة لايمكنك ارسالها بالمرجع ByRef الى الاجراءات –سواء Subs او Functions.
قد يأتي احد مبرمجي المتمرسين ويقترح علي تعريف الخصائص على شكل متغيرات في الفئات:
' TestClass في الملف
Public TestProperty As Integer
لقد وقعت في الفخ يا صديقي العزيز! وذلك ان VB6 لغة الحالات الشاذة، فالشيفرة السابقة قد قامت بتعريف الإجراءات Property Let و Property Set مخفية (حتى يتم التوافق مع COM)، مما يعني انك لن تستطيع ارسال قيم الخصائص بالمرجع.
ولكن مع VB.NET فهو يقدم فكرة الحقول Fields التي تمكنك من ارسال القيم بالمرجع، ليس هذا فقط بل حتى الخصائص يمكن ارسالها بالمرجع.
2) المشيدات لا تقبل وسيطات
اثبت VB6 قوة تطبيق مبدأ التغليف Encapsulation في فئاته حيث يوفر امكانية تعريف المشيدات Constructors في الفئات. ولكن مع الاسف الشديد لا يمكنك اضافة الوسيطات الهامة Parameters في المشيدات حتى تحمي فئاتك من الاخطاء، فلو وجدت خصائص ضرورية عليك كتابة معروض الى مستخدم الفئة وكتابة كافة قصائد المدح والرجاء حتى يوافق ويتذكر اسناد قيم هذه الخصائص بعد انشاء الكائن.
اما مع VB.NET فكل ما هو مطلوب منك تعريف الوسطيات المطلوبة في مشيدها:
' *** VB.NET **********
Class TestClass
Sub New (x As Integer, Y As String)
…
End Sub
End Class
3) اعادة التعريف
اعادة التعريف Overloading غير مدعومة في VB6، مما يعني كتابة عشرات الجمل الشرطية قبل استدعاء الطرق، وذلك حتى يتم التحقق من النوع المناسب لوسيطات الطريقة:
' *** VB6 **********
If VarType(x) = 20 Then ' String
MyObject.OpenStringMethod(x)
ElseIf VarType(x) = 2 Then ' Integer
MyObject.OpenIntegerMethod(x)
ElseIf … Then
...
ElseIf … Then
…
End IF
الشيفرة السابقة تفترض ان الطريقة تستقبل وسيطة واحدة، ولكن تخيل انها تستقبل اكثر من وسيطة:
' *** VB6 **********
If VarType(x) = 20 And VarType(y) = 2 Then
MyObject.StringIntegerMethod(x, y)
ElseIf VarType(x) = 20 And VarType(y) = 20
MyObject.StringStringMethod(x, y)
ElseIf VarType(x) = 2 And VarType(y) = 20
MyObject.IntegerStringMethod(x, y)
ElseIf VarType(x) = 2 And VarType(y) = 2
MyObject.IntegerIntegerMethod(x, y)
…
End IF
لا تعليق !!!
4) إجراءات الاحداث تعرف وقت التصميم فقط
عندما تنوي تعريف اجراء ليقنص حدث ما، فهذا الاجراء سيتم تعريفه وقت التصميم Design Time فقط، ولايمكن اجراء عملية القنص وقت التنفيذ Run Time، وذلك بسبب الصيغة الغريبة التي يتبعها VB6 لقنص الحدث:
' *** VB6 **********
Sub ObjectName_EventName ()
…
End Sub
ولكن مع VB.NET فهو يمكنك من تحديد الاجراء وقت التنفيذ باستخدام الامر AddHandler:
' *** VB.NET **********
AddHandler MyObject.Event, AddressOf (MySub)
5) المتغيرات العامة Public لابد ان تكون متوافقة مع COM
فالمتغيرات الحرفية ثابتة الطول Fixed-Length Strings والمصفوفات Arrays لايمكن ان تكون Public.
6) تحتاج الى ساحر لتطبيق حلقة For Each على فئات المجموعات
قمت بعد سهر وتعب بتطوير فئة مجموعة Collection Class، واردت ان تكون متوافقة مع مواصفات ومعايير COM وذلك بإعطائها قابلية استخدام الحلقة For Each معها. للاسف الشديد VB6 لا يمكنك من فعل ذلك، لذلك عليك التوغل في واجهات COM وتعريف اجراء من الواجهة IUnknown ليعود بالواجهة IEnumVariant والتي لن تستطيع الحصول عليها الا من كائن من النوع Collection (يدعم هذه الواجهة) وكتابة هذه الشيفرة الغريبة:
' *** VB6 **********
Public Property Get NewEnum() As IUnknown
Set NewEnum = m_CollectionObject.[_NewEnum]
End Property
الم اقل لك انك تحتاج الى ساحر؟
ولكن مع VB.NET فهو يمكنك من تطبيقها دون اللجوء الى السحرة والمشعوذين، فيكفي تضمين واجهات مقدمة من اطار عمل .NET (واضحة المعنى والمضمون) في فئاتك لتدعم هذه الحلقة.
7) ماذا عن الوراثة؟
الوراثة Inheritance للاسف الشديد غير مدعومة، وعملية محاكاة الوراثة (باستخدام التفويض Delegation) اثبتت فشلها الذريع. لن اتحدث عن فائدة الوراثة وما تقدمه لك، وسأكتفي بقول: إلي ما يعرف الصقر يشويه!
8) اسناد قيم الكائنات (ضرورة Set)
من الاشياء التي اثمرت في نمو الشوائب Bugs في برامج VB6 هي ضرورة استخدام Set عند الحديث عن عملية اسناد القيم بين الكائنات، اما ان تجاهلها المبرمج فلن تظهر رسالة خطأ، وذلك بسبب الخصائص الافتراضية Default Propeties التي يدعمها VB6، فالشيفرة التالية:
' *** VB6 **********
MyObject = YourObject
لا نعلم هل تسبب خطأ وقت التنفيذ او لا.
9) فئات الانعكاس Reflection Classes
لاتوجد طريقة واضحة وسهلة في VB6 تمكننا من معرفة جميع الفئات واعضائها التي تحتويها مكونات COM، وان اردت ذلك عليك اتقان لغة خاصة بـ COM (والتي تسمى Interface Definition Language – (IDL) تشبه الى حد كبير لغة C.
ولكن مع VB.NET فيمكن معرفة كل شئ عن مكونات .NET عن طريقة مجموعة من الفئات تسمى فئات الانعكاس Reflection Classes واستخدامها يتم بنفس لغة البرمجة VB.NET وليس لغة اخرى.
10) الاحداث تعتمد على المؤشرات وليس الكائنات.
من الاشياء المحزنة والمخزية في VB6 هو فلسلفة تطبيقه لعملية قنص الاحداث، حيث ان العبارة WithEvents تتبع المؤشر وليس الكائن:
' *** VB6 **********
Dim WithEvents X As TestClass
...
...
Sub X_EventName()
...
End Sub
ان تم نسخ الكائن الى مؤشر اخر وتم قتل المؤشر الاصلي X فلن يتم تنفيذ الحدث EventName:
' *** VB6 **********
Dim Y As TestClass
Y = X
X = Nothing
ولكن مع VB.NET فيمكنك قنص الاحداث استنادا الى كائناتها عوضا عن مؤشراتها.
11) حفظ بيانات الكائنات او نسخها (تسلسل الكائنات)
لاتوجد ميكانيكية واضحة تمكن مبرمجي VB6 من حفظ بيانات الكائنات الموجودة في الذاكرة، ولا حتى نسخها من كائن الى كائن. وان قمت بعمل ذلك بشكل يدوي وكتابة عشرات الشيفرات المصدرية، فعليك تعديل هذه الشيفرة في كل مرة تضيف خاصية في الفئة. ليس هذا فقط، بل عليك اضافة شيفرات اضافية ايضا في كل مرة تعدل فيها المتغيرات الستاتيكية Static Variables في اجراءات الفئة.
ولكن مع VB.NET فهو يمكنك من عمل هذا بفضل مجموعة من الفئات مقدمة من اطار عمل .NET تمكنك من نسخ الكائنات وحفظها وهو ما يمسى تسلسل الكائنات Object Serialization.
12) New لا تنشئ الكائن حتى يتم استدعاء احد طرقه
الكلمة المحجوزة New تنشئ كائن جديد، في الحقيقة ليس دائما:
' *** VB6 **********
Dim obj As New TestClass
عند استخدام New لحظة تعريف المتغير –كما بالشيفرة السابقة- فلن يتم انشاء الكائن حتى تستدعي احد اعضاءه.
هذه الخزعبلات لن تجدها مع VB.NET.
13) المرجعية الدائرية Circular Reference
من اكبر الصعاب التي واجهة المبرمجين مشكلة المرجعية الدائرية Circular Reference، والتي تبقي كائنين على قيد الحياة بسبب وجود مؤشر في كل كائن يشير الى الكائن الاخر:
' *** VB6 **********
' Person.cls في الملف
Public Name As String
Public Brother As Person
عن انشاء كائنات من هذه الفئة، واحداث مرجعية دائرية بينهما (عن طريق الخاصية Brother):
' *** VB6 **********
Dim X As New Person
Dim Y As New Person
X.Name = "عباس السريع"
Y.Name = "عبود اللوح"
Set X.Brother = Y
Set Y.Brother = X
فان الكائنين سيبقيان في الذاكرة حتى وان اختف مؤشراتهما، لا تصدق جرب واكتب شيئا مثل:
Set X = Nothing
Print Y.Brother.Name ' عباس السريع
ولكن مع VB.NET فلن تحدث مشكلة المرجعية الدائرية ابدا، وذلك بفضل المجموعة Garbage Collection (GC) والتي بها ميكانيكية ذكية تزيل كافة الكائنات من الذاكرة والتي لا تشير لها مؤشرات في قابلة للوصول من الشيفرة المصدرية.
كان هذا كل ما وددت ذكره حول الفئات والكائنات مع VB6، في المرة القادمة سنأخذ جولة سريع حول النماذج Forms ونرى قصور رمز وسبب نجاح VB6 (النماذج Forms).
-- تركي