هل من المقبول استدعاء طريقة افتراضية من Dispose أو destructor؟

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

  •  02-07-2019
  •  | 
  •  

سؤال

لا يمكنني العثور على مرجع لها ولكني أتذكر أنني قرأت أنه لم يكن من الجيد استدعاء الأساليب الافتراضية (متعددة الأشكال) داخل أداة التدمير أو طريقة Dispose() الخاصة بـ IDisposable.

هل هذا صحيح وإذا كان الأمر كذلك فهل يمكن لأحد أن يشرح السبب؟

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

المحلول

استدعاء الأساليب الافتراضية من أداة الإنهاء/Dispose غير آمن، لنفس الأسباب من غير الآمن القيام به في المنشئ.من المستحيل التأكد من أن الفئة المشتقة لم تقم بالفعل بتنظيف بعض الحالات التي تتطلب الطريقة الافتراضية تنفيذها بشكل صحيح.

يرتبك البعض من النمط القابل للتصرف القياسي، واستخدامه للطريقة الافتراضية، virtual Dispose(bool disposing), ، وأعتقد أن هذا يجعله مناسبًا للاستخدام أي الطريقة الافتراضية أثناء التخلص.خذ بعين الاعتبار الكود التالي:

class C : IDisposable {
    private IDisposable.Dispose() {
        this.Dispose(true);
    }
    protected virtual Dispose(bool disposing) {
        this.DoSomething();
    }

    protected virtual void DoSomething() {  }
}
class D : C {
    IDisposable X;

    protected override Dispose(bool disposing) {
        X.Dispose();
        base.Dispose(disposing);
    }

    protected override void DoSomething() {
        X.Whatever();
    }
}

إليك ما يحدث عند التخلص من كائن من النوع D, ، مُسَمًّى d:

  1. بعض مكالمات الكود ((IDisposable)d).Dispose()
  2. C.IDisposable.Dispose() يستدعي الطريقة الافتراضية D.Dispose(bool)
  3. D.Dispose(bool) يتخلص من D.X
  4. D.Dispose(bool) المكالمات C.Dispose(bool) بشكل ثابت (هدف المكالمة معروف في وقت الترجمة)
  5. C.Dispose(bool) يستدعي الطرق الافتراضية D.DoSomething()
  6. D.DoSomething يدعو الطريقة D.X.Whatever() على التخلص منها بالفعل D.X
  7. ?

الآن، معظم الأشخاص الذين يقومون بتشغيل هذا الرمز يفعلون شيئًا واحدًا لإصلاحه - إنهم ينقلون الملف base.Dispose(dispose) اتصل بهم قبل تنظيف الأشياء الخاصة بهم.ونعم، هذا يعمل.ولكن هل تثق حقًا في Programmer X، المطور المبتدئ جدًا من الشركة التي طورتها؟ C ل، المخصصة للكتابة D, ، لكتابته بطريقة يتم من خلالها اكتشاف الخطأ أو اكتشافه base.Dispose(disposing) استدعاء في المكان الصحيح؟

أنا لا أقول أنه لا ينبغي عليك أبدًا، أبدًا اكتب رمزًا يستدعي طريقة افتراضية من Dispose، وهو ما ستحتاج إليه فقط وثيقة تلك الطريقة الافتراضية متطلبات أنه لا يستخدم أبدًا أي حالة تم تعريفها في أي فئة مشتقة أدناه C.

نصائح أخرى

لا يتم تشجيع الأساليب الافتراضية في كل من المنشئين والمدمرين.

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

لا أعتقد أن هناك أي توصية ضد الاتصال بالطرق الافتراضية.قد يكون الحظر الذي تتذكره هو القاعدة ضد الإشارة إلى الكائنات المُدارة في أداة الإنهاء.

يوجد نمط قياسي تم تحديده في وثائق .Net لكيفية تنفيذ Dispose().تم تصميم النموذج بشكل جيد للغاية، وينبغي متابعته عن كثب.

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

عندما يتم تمرير قيمة Dispose(bool) إلى false، فهذا يشير إلى أن أداة الإنهاء قد استدعت طريقة التخلص.في هذه الحالة، يجب محاولة تنظيف الكائنات غير المُدارة فقط (باستثناء بعض الحالات النادرة).والسبب في ذلك هو حقيقة أن جامع البيانات المهملة قد استدعى للتو طريقة الإنهاء، لذلك يجب أن يتم وضع علامة على الكائن الحالي بأنه جاهز للإنهاء.لذلك، قد يتم أيضًا وضع علامة على أي كائن يشير إليه للقراءة للإنهاء، وبما أن التسلسل غير حتمي، فقد يكون الإنهاء قد حدث بالفعل.

أوصي بشدة بالبحث عن نمط Dispose() في وثائق .Net ومتابعته بدقة، لأنه من المحتمل أن يحميك من الأخطاء الغريبة والصعبة!

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

على الرغم من أنني لا أعتقد أن هناك "قاعدة" فيما يتعلق بالسلوك هنا.لكن الفكرة العامة هي أنك تريد عزل عملية تنظيف الموارد لتلك الحالة فقط على هذا المستوى من التنفيذ.

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