مدة بقاء الكائن: كيفية إنشاء و إتلاف الكائنات
مثيل الفئة، كائن، يتم إنشائه باستخدام الكلمة الأساسية New. مهام التهيئة غالباً يجب أن يتم تنفيذها على كائنات جديدة قبل استخدامها. مهام التهيئة تتضمن فتح الملفات، الاتصال بقواعد بيانات، وقراءة قيم من مفاتيح التسجيل. Visual Basic يتحكم في تهيئة الكائنات الجديدة باستخدام إجراءات تسمى المُنشئات (أساليب خاصة تسمح بالتحكم في التهيئة).
بعد أن يترك كائن نطاق، يتم تحريره بواسطة لغة وقت التشغيل العامة (CLR). يتحكم Visual Basic بطرح موارد النظام باستخدام إجراءات تسمى مدمّرات. معاً، المُنشئات و المدمّرات تدعم إنشاء مكتبات فئة قوية و يمكن توقعها.
استخدام المُنشئات و المدمّرات
المُنشئات و المدمّرات تتحكم بإنشاء وتدمير الكائنات. الإجراءات Sub New و Sub Finalize في Visual Basic تهيئ و تدمر الكائنات; تقوم باستبدال الأساليب Class_Initialize و Class_Terminate المستخدمة في الإصدارات 6.0 من Visual Basic والإصدارات الأقدم.
فرعي جديد
المنشئ Sub New يمكنه أن ينفذ مرة واحدة فقط عند إنشاء فئة. لا يمكن استدعائه بشكل صريح في أي مكان آخر غير أول سطر في التعليمات البرمجية لمُنشئ آخر أما من نفس الفئة أو من فئة مشتقة. علاوة على ذلك، التعليمات البرمجية في أسلوب Sub New يتم تنفيذها دوماً قبل أي تعليمات برمجية أخرى في الفئة. Visual Basic 2005 و الإصدارات الأحدث ينشأ ضمنيًا المنشئ Sub New في وقت التشغيل إذا لم تقم بتعريف إجراء Sub New لفئة بشكل صريح.
لإنشاء مُنشئ لفئة ، قم بإنشاء إجراء باسم Sub New في أي مكان في تعريف الفئة. لإنشاء منشئ ذو معلمات، قم بتعيين أسماء و أنواع بيانات الوسائط لـ Sub New كما تعيّن وسائط لأي إجراء أخر، كما في التعليمات البرمجية التالية:
Sub New(ByVal s As String)
المُنشئات كثيرا ما تكون محملة بشكل زائد، كما هو موضح في التعليمات البرمجية التالية:
Sub New(ByVal s As String, i As Integer)
عند تعريف فئة مشتقة من فئة أخرى، أول سطر للمنشئ يجب أن يكون استدعاء لمُنشئ الفئة الأساسية، إلا إذا كان للفئة الأساسية مُنشئ يمكن الوصول إليه ولا يأخذ أية معلمات. الاستدعاء لفئة أساسية تحتوي على المُنشئ أعلاه، على سبيل المثال، يكون MyBase.New(s). وإلا، كان MyBase.New اختياري، و وقت تشغيل Visual Basic يستدعيه ضمنياً.
بعد كتابة التعليمات البرمجية لاستدعاء مُنشئ الكائن الأصل، يمكنك إضافة أية تعليمات برمجية لتهيئة إضافية للإجراء Sub New. Sub New يمكن أن يقبل وسائط عند استدعائه كمنشئ ذو معلمات. يتم تمرير هذه المعلمات من الإجراء الذي يستدعي المنشئ، على سبيل المثال، Dim AnObject As New ThisClass(X).
إنهاء فرعي
قبل تحرير الكائنات، يستدعي CLR تلقائياً الأسلوب Finalize للكائنات التي تعرّف الإجراء Sub Finalize. الأسلوب Finalize يمكنه أن يحتوي على تعليمات برمجية تحتاج ليتم تنفيذها قبل إتلاف كائن، مثل تعليمات برمجية لإغلاق الملفات وحفظ معلومات الحالة. هناك انخفاض بسيط في الأداء بسبب تنفيذ Sub Finalize، لذا يجب أن تقوم بتعريف الأسلوب Sub Finalize فقط عندما تحتاج لطرح كائنات بشكل صريح.
ملاحظة
حاوي المهملات في CLR لا (ولا يستطيع أن) يتخلص من الكائنات غير المُدارة ، كائنات يتم تنفيذها مباشرة من قبل نظام التشغيل، خارج بيئة وقت تشغيل اللغات العام (CLR). وهذا لأن الكائنات غير المُدارة المختلفة يجب أن يتم الخلص منها بطرق مختلفة. تلك المعلومات غير مقترنة مباشرة مع الكائن غير المُدار; يجب أن يتم العثور عليها في الوثائق الخاصة بالكائن. يجب على الفئة التي تستخدم الكائنات غير المُدارة التخلص منها في أسلوب Finalize الخاص بها.
المدمّر Finalize هو أسلوب محمي يمكن استدعائه فقط من الفئة التي ينتمي إليها، أو من فئات مشتقة. يستدعي النظام Finalize تلقائياً عند إتلاف كائن، لذلك عليك أن لا تستدعي Finalize بشكل صريح من خارج تطبيق Finalize لفئة مشتقة.
بعكس، Class_Terminate، الذي ينفذ بمجرد تعيين كائن إلى لا شيئ ، يوجد عادةً تأخير بين فقدان كائن للنطاق و استدعاء Visual Basic للمدمّر Finalize. يتيح Visual Basic 2005 والإصدارات اللاحقة لنوع ثاني من المدمّر، Dispose، الذي يمكن استدعائه بشكل صريح في أي وقت لطرح موارد فوراً.
ملاحظة
مدمّر Finalize لا يجب أن يطرح استثناءات، لأنه لا يمكن معالجتها من قبل التطبيق كما يمكن أن تؤدي إلى إنهاء التطبيق.
كيف تعمل الأساليب جديد و إنهاء في التسلسل الهيكلي لفئة
كلما تم إنشاء مثيل لفئة، يحاول وقت تشغيل اللغة العامة (CLR) تنفيذ إجراء باسم New، إذا كان موجوداً في ذلك الكائن. New هو نوع لإجراء يسمى constructor يُستخدم لتهيئة كائنات جديدة قبل أية تعليمات برمجية أخرى في تنفيذ كائن. المنشئ New يمكن استخدامه لفتح ملفات، الاتصال بقواعد البيانات، تهيئة المتغيرات، و تولي أية مهام أخرى تحتاج إلى أن يتم الانتهاء منها قبل استخدام الكائن.
عند إنشاء مثيل لفئة مشتقة، ينفذ مُنشئ الفئة الأساسية Sub New أولاً، ثم مُنشئات الفئات المشتقة. هذا يحدث لأن السطر الأول من التعليمات البرمجية في المنشئ Sub New يستخدم بناء الجملة MyBase.New() لاستدعاء منشئ الفئة الأعلى منه حالاً في التسلسل الهيكلي للفئة. ثم يتم استدعاء المنشئ Sub New لكل فئة في التسلسل الهيكلي للفئة إلى أن يتم الوصول إلى منشئ الفئة الأساسية. في هذه المرحلة، التعليمات البرمجية في منشئ الفئة الأساسية يتم تنفيذها، متبوعة بالتعليمات البرمجية في كل مُنشئ في كل الفئات المشتقة و التعليمات البرمجية في الفئات الأكثر اشتقاقاً يتم تنفيذها بالنهاية.
عندما لا يصبح هناك حاجة لكائن، يستدعي CLR الأسلوب Finalize لذلك الكائن قبل تحرير الذاكرة الخاصة به. الأسلوب Finalize يسمى destructor لأنه يقوم بإجراء مهام تنظيف، مثل حفظ معلومات الحالة، إغلاق الملفات و اتصالات لقواعد البيانات، و مهام أخرى يجب أن تتم قبل تحرير كائن.
واجهة IDisposable
مثيلات فئة تتحكم غالبا بموارد غير مدارة من قبل (CLR) ، مثل معالجة Windows و اتصالات قاعدة البيانات. يجب أن يتم التخلص من هذه الموارد في أسلوب الفئة Finalize، بحيث سيتم تحريرها عند إتلاف الكائن بواسطة حاوي المهملات. ومع ذلك، يقوم حاوي المهملات بإتلاف الكائنات فقط عندما يتطلب CLR ذاكرة أكثر. وهذا يعني أن الموارد قد لا يتم تحريرها حتى بعد فترة طويلة من خروج الكائن من النطاق.
لتكملة تجميع البيانات المهملة، يمكن أن توفر الفئات الخاصة بك آلية لإدارة موارد النظام بفعالية إذا قامت بتطبيق الواجهة IDisposable. IDisposable له أسلوب واحد، Dispose، الذي يجب على العملاء استدعائه عند الانتهاء من استخدام كائن. يمكنك استخدام الأسلوب Dispose لتحرير الموارد فوراً و إنجاز مهام مثل إغلاق الملفات و اتصالات قاعدة بيانات. بعكس المدمّر Finalize، لا يتم استدعاء الأسلوب Dispose تلقائياً. يجب على عملاء الفئة استدعاء Dispose بشكل صريح عندما تريد تحرير موارد فوراً.
تطبيق IDisposable
الفئة التي تطبق الواجهة IDisposable يجب أن تتضمن مقاطع التعليمات البرمجية هذه:
حقل لتتبع ما إذا كان الكائن قد تم التخلص منه:
Protected disposed As Boolean = False
تحميل زائد لـDispose الذي يحرر موارد الفئة. هذا الأسلوب يجب أن يتم استدعائه من قبل أساليب الفئة الأساسية Dispose و Finalize:
Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposed Then If disposing Then ' Insert code to free managed resources. End If ' Insert code to free unmanaged resources. End If Me.disposed = True End Sub
تطبيق Dispose يحتوي على التعليمات البرمجية التالية:
Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub
تجاوز الأسلوب Finalize الذي يحتوي على التعليمات البرمجية التالية فقط:
Protected Overrides Sub Finalize() Dispose(False) MyBase.Finalize() End Sub
الاشتقاق من فئة تطبّق IDisposable
الفئة التي تشتق من فئة أساسية تطبّق واجهة IDisposable لا تحتاج إلى تجاوز أي من الأساليب الأساسية ما لم تستخدم موارد إضافية تحتاج التخلص منها. في هذه الحالة، يجب على الفئة المشتقة تجاوز أسلوب الفئة الأساسية Dispose(disposing) للتخلص من موارد الفئة المشتقة. هذا التجاوز يجب أن يستدعي أسلوب الفئة الأساسية Dispose(disposing).
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposed Then
If disposing Then
' Insert code to free managed resources.
End If
' Insert code to free unmanaged resources.
End If
MyBase.Dispose(disposing)
End Sub
يجب أن لا تتجاوز الفئة المشتقة أساليب الفئة الأساسية Dispose و Finalize. عندما يتم استدعاء الأساليب تلك من مثيل للفئة المشتقة، تطبيق الفئة الأساسية لتلك الأساليب يستدعي تجاوز الفئة المشتقة للأسلوب Dispose(disposing).
تجميع البيانات المهملة و إنهاء المدمّر
يستخدم .NET Framework النظام تتبع مرجع تجميع البيانات المهملة لتحرير الموارد غير المستخدمة بشكل دوري. استخدم Visual Basic 6.0 والإصدارات السابقة نظام مختلف يسمى عد المرجع لإدارة الموارد. على الرغم من أن كلّا النظامين يقومان بتنفيذ نفس الوظيفة تلقائياً، توجد بعض الاختلافات الهامة.
يتلف CLR الكائنات بشكل دوري عندما يحدد النظام أن هذه الكائنات لم تعد هنالك حاجة إليها. يتم تحرير الكائنات بسرعة أكبر عندما تكون موارد النظام قليلة، و بشكل أبطأ خلاف ذلك. التأخير بين فقدان كائن للنطاق و تحرير CLR له يعني أنه، بخلاف الكائنات في Visual Basic 6.0 والإصدارات السابقة، لا يمكنك تحديد تماماً متى يتم إتلاف الكائن. في مثل هذه الحالة، توصف الكائنات بأن لها مدة بقاء غير قابلة للتحديد. في معظم الحالات، مدة البقاء الغير قابلة للتحديد لا تغيّر كيفية كتابتك للتطبيقات، طالما تتذكر أن المدمّر Finalize قد لا يقوم حالاً بالتنفيذ عندما يفقد كائن النطاق.
فرق آخر بين أنظمة تجميع البيانات المهملة تتضمن استخدام Nothing. للاستفادة من عد المرجع في Visual Basic 6.0 والإصدارات السابقة، يقوم المبرمجين أحياناً بتعيين Nothing لمتغيرات الكائن لتحرير المراجع التي تقيّدها هذه المتغيرات. إذا قيّد المتغير أخر مرجع للكائن، تم تحرير موارد الكائن فوراً. في الإصدارات اللاحقة من Visual Basic، بينما قد يكون هناك حالات يكون فيها هذا الإجراء لا يزال ذو قيمة، تنفيذه لا يؤدي أبداً لتحرير موارد الكائن المشار إليه فوراً. لتحرير موارد مباشرة، استخدم أسلوب الكائن Dispose، إذا كانت متوفرة. الحالة الوحيدة التي يجب عليك تعيين متغير إلى Nothing هي عندما تكون مدة بقاءه طويل بالنسبة إلى الوقت الذي يأخذه حاوي المهملات للكشف عن الكائنات المعزول.