في نمط IDisposable، هل يجب على الفئة الأساسية أن تسمح للفئات المشتقة بمشاركة العلامة التي تم التخلص منها؟

StackOverflow https://stackoverflow.com/questions/1079752

  •  21-08-2019
  •  | 
  •  

سؤال

أعمل حاليًا على إصلاح قاعدة تعليمات برمجية c# التي لا تحتوي على نمط جيد لاستخدام التخلص.

إنها قاعدة تعليمات برمجية كبيرة، وهي قاعدة تعليمات برمجية تتطلب موارد وتستخدم العديد من مكتبات C++ المخصصة غير المُدارة على المستوى المنخفض.

لدي فهم جيد لنمط التخلص.لقد أمضيت بعض الوقت في فهم ما أعتقد أنه المقال المعياري الذهبي حول هذه القضية: مقال التخلص من جو دافي

في محاولة لتقليل تكرار التعليمات البرمجية، كنا نفكر في بعض الفئات المساعدة للتخلص، ومن ثم سؤالي:

إذا كانت الفئة الأساسية تنفذ نمط التخلص القياسي، فهل يجب أن تسمح بمشاركة العلامة التي تم التخلص منها، على سبيل المثال.تم وضع علامة على أنها محمية؟

للتوضيح أعني هل يجب أن يكون هناك حالة منطقية واحدة فقط ضمن التسلسل الهرمي للميراث الذي يحدد ما إذا كان قد تم التخلص من مثيل الكائن أم هل يجب أن يكون هناك منطقية خاصة في كل خطوة من سلم الميراث؟

تقوم الأمثلة الموجودة في MSDN وفي الرابط أعلاه بتعيين علامة على كل مستوى، ولكنها لا تشرح أبدًا السبب الكامن وراء ذلك.أنا في رأيين بشأن هذه القضية، ما هي أفكارك وأسبابك؟

هل كانت مفيدة؟

المحلول

أود أن أقول لا، لا ينبغي أن نشارك العلم.تؤدي مشاركة العلم إلى خلق فرص للفشل والتي يمكن أن يمنعها التغليف الأفضل.

على سبيل المثال، ضع في اعتبارك السيناريو الذي يكون لديك فيه خاصية تم التخلص منها للقراءة فقط في الفئة الأساسية.يتم تعيين حقل الدعم على "صحيح" فقط في طريقة التخلص (التخلص) في الفئة الأساسية.هذا يعني أن الخاصية Disposed لا يمكن أن تعود صحيحة إلا إذا تم استدعاء الفئة الأساسية Dispose (باستثناء الانعكاس الشرير بالطبع).وهذا يسمح للفئة الأساسية بتقديم عقد قابل للتنفيذ.

الآن فكر في العكس، حيث يوجد جهاز ضبط محمي.يمكن لأي فئة الآن تعيين الخاصية "تم التخلص" بشكل تعسفي إلى "صحيح" دون التخلص من أي شيء.يؤدي هذا إلى إنشاء فرصة لإرجاع "التخلص" إلى الوضع الصحيح عندما لا يتم التخلص من أي شيء.

سأختار الخيار الأول لأنه يوفر العقد الأكثر قابلية للتنفيذ.

نصائح أخرى

أوصي بالحصول على خاصية تم التخلص منها في الفئة الأساسية باستخدام أداة عامة ومحددة محمية.

في حالة وجود طرق يجب أن تفعل شيئًا مختلفًا عند التخلص من الفصل، على سبيل المثال طرح استثناء، سأقوم بإنشاء خاصية getter محمية فقط للفئة الأساسية التي تقرأ الحقل الخاص في الفئة الأساسية.بهذه الطريقة تسمح لأي وريث بمعرفة ما إذا كان قادرًا على إجراء عملية ما.

بعد ذلك، لمعرفة ما إذا كان قد تم بالفعل التخلص من الفصل في طريقة التخلص الخاصة به (على سبيل المثال:لتجنب إطلاق الموارد مرتين)، أعتقد أن وجود علامة خاصة أفضل للوضوح والصيانة.

بالإضافة إلى إجابة JaredPar، أود أن أضيف أنه ليس من الضروري دائمًا أن يكون هناك _disposed علَم.في كثير من الأحيان، توفر الحقول الأخرى "المتعلقة بالموارد" للكائن بشكل طبيعي طريقة لتمثيل الحالة التي تم التخلص منها.

على سبيل المثال، كائن COM خارجي يجب أن يكون Shutdown قبل أن يتم التخلص منه، سيتم تمثيله بالإشارة إلى كائن COM، وبالتالي الجزء ذي الصلة منه Dispose سيكون:

if (_comObject != null)
{
    _comObject.Shutdown();
    _comObject = null;
}

يمكن تشغيل هذا بأمان عدة مرات دون الاتصال Shutdown أكثر من مرة حسب الحاجة.الطرق الأخرى التي تحاول استخدام _comObject بعد Dispose سوف تحصل على NullReferenceException, ، أو من الأفضل أن تتحقق هذه الطرق من حقل _comObject وترميه ObjectDisposedException.

أجد أن هذا صحيح في كثير من الأحيان - بعد أن قمت بتنفيذ IDisposable بشكل متكرر، لا أستطيع أن أتذكر أنني كنت بحاجة إلى برنامج منفصل _disposed مجال.إن تقديم واحدة من شأنه أن يزيد من درجات الحرية (يزيد من عدد الطرق التي يمكنني من خلالها إفسادها).

لذلك من غير المرجح أن يكون هذا مفيدًا للفئات المشتقة حتى لو كانت فكرة آمنة (وهي ليست كذلك، كما يوضح JaredPar).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top