فحص أدوات الإنهاء للفئة
يتم استخدام أدوات الإنهاء (يشار إليها تاريخيا باسم destructors) لإجراء أي تنظيف نهائي ضروري عند تجميع مثيل فئة بواسطة جامع البيانات المهملة (GC). في معظم الحالات، يمكنك تجنب كتابة أداة الإنهاء باستخدام System.Runtime.InteropServices.SafeHandle أو الفئات المشتقة لتضمين أي مقبض غير مدار.
بعض الأشياء التي يجب وضعها في الاعتبار عند استخدام أدوات الإنهاء:
- لا يمكن تعريف الإنهاءات في أنواع
struct. يتم استخدامها فقط مع الفصول الدراسية. - يمكن أن تحتوي الفئة على أداة إنهاء واحدة فقط.
- لا يمكن توريث أدوات الإنهاء أو تحميلها بشكل زائد.
- لا يمكن استدعاء أدوات الإنهاء. يتم استدعاؤها تلقائيا.
- لا تأخذ أداة الإنهاء المعدلات أو تحتوي على معلمات.
بناء جملة أداة الإنهاء
في C#، يتم تعريف المنهي باستخدام tilde (~) متبوعا باسم الفئة. لا يأخذ أي معلمات ولا يمكن استدعاؤه بشكل صريح.
class Car
{
~Car() // finalizer
{
// cleanup statements...
}
}
يمكن أيضا تنفيذ أداة الإنهاء كتعريف نص تعبير، كما يظهر المثال التالي.
public class Destroyer
{
public override string ToString() => GetType().Name;
~Destroyer() => Console.WriteLine($"The {ToString()} finalizer is executing.");
}
العلاقة بين جمع البيانات المهملة وملفات الإنهاء
يدير مجمع البيانات المهملة في .NET تلقائيا تخصيص الذاكرة وإصدارها للكائنات المدارة. عندما لا تتم الإشارة إلى كائن بعد الآن، فإن GC يضع علامة عليه للمجموعة ويستعيد ذاكرته في النهاية. إذا كانت الفئة تحتوي على أداة إنهاء، فإن GC تستدعي الإنهاء قبل استعادة ذاكرة الكائن. تسمح أداة الإنهاء للكائن بتحرير أي موارد غير مدارة يحتفظ بها.
تتضمن عملية التسوية عادة الخطوات التالية:
- عندما تكتشف GC أنه لم يعد من الممكن الوصول إلى كائن مع أداة إنهاء، فإنه ينقل الكائن إلى قائمة انتظار الإنهاء.
- ينفذ مؤشر ترابط الإنهاء أسلوب الإنهاء.
- بعد تشغيل الإنهاء، يتم نقل الكائن إلى قائمة انتظار
freachableGC، حيث يكون مؤهلا لجمع البيانات المهملة في دورة GC التالية.
مثال على أداة الإنهاء
public class ResourceHolder
{
// Unmanaged resource
private IntPtr unmanagedResource;
// Constructor
public ResourceHolder()
{
// Allocate unmanaged resource
unmanagedResource = /* allocate resource */;
}
// Finalizer
~ResourceHolder()
{
// Release unmanaged resource
if (unmanagedResource != IntPtr.Zero)
{
// Free the resource
/* free resource */
unmanagedResource = IntPtr.Zero;
}
}
}
تنفيذ نمط التخلص باستخدام أداة الإنهاء
تستخدم واجهات مثل IDisposableIAsyncDisposable لتحرير الموارد بشكل محدد. يتم استدعاء أسلوب Dispose بشكل صريح لتحرير الموارد، بينما يعمل المنهي كشبكة أمان لضمان تحرير الموارد حتى إذا لم يتم استدعاء Dispose.
مهم
إنشاء الواجهات واستخدامها خارج نطاق هذه الوحدة النمطية. ويرد وصف لاستخدام IDisposable هنا لتوفير سياق لنمط "التخلص". يتوفر التدريب الذي يوفر مقدمة للواجهات على النظام الأساسي ل Microsoft Learn.
ضع النقاط التالية في الاعتبار عند استخدام أدوات الإنهاء:
- إن أدوات الإنهاء غير محددة، ما يعني أنه لا يمكنك التنبؤ بموعد تشغيل الإنهاء. يعتمد ذلك على جدول GC. يمكن أن يؤدي هذا السلوك إلى تأخيرات في تحرير الموارد غير المدارة.
- يمكن أن تؤثر أدوات الإنهاء على الأداء لأن الكائنات مع أدوات الإنهاء تستغرق وقتا أطول لتجميعها.
- يوصى بتنفيذ واجهة
IDisposableوطريقةDisposeللتنظيف المحدد للموارد. يمكن استدعاء أسلوبDisposeبشكل صريح لتحرير الموارد، ويمكن استخدام الإنهاء كشبكة أمان.
فيما يلي مثال على فئة تنفذ واجهة IDisposable وأداة الإنهاء:
public class ResourceHolder : IDisposable
{
// Unmanaged resource
private IntPtr unmanagedResource;
private bool disposed = false;
// Constructor
public ResourceHolder()
{
// Allocate unmanaged resource
unmanagedResource = /* allocate resource */;
}
// Dispose method
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Free other managed objects
}
// Free unmanaged resources
if (unmanagedResource != IntPtr.Zero)
{
/* free resource */
unmanagedResource = IntPtr.Zero;
}
disposed = true;
}
}
// Finalizer
~ResourceHolder()
{
Dispose(false);
}
}
في هذا المثال:
- يتم استدعاء أسلوب
Disposeلتحرير الموارد بشكل محدد. - يستدعي المنهي
Dispose(false)لتحرير الموارد غير المدارة إذا لم يتم استدعاءDispose. - يتم استخدام
GC.SuppressFinalize(this)لمنع تشغيل المنهي إذا تم استدعاءDisposeبالفعل.