سؤال

أتلقى تحذيرًا عندما أقوم بتشغيل بعض التعليمات البرمجية من خلال أداة تحليل رمز Visual Studio والتي لست متأكدًا من كيفية حلها. ربما صادف شخص ما هنا قضية مماثلة ، وحلها ، وهو على استعداد لتبادل رؤيتهم.

أنا أقوم برمجة خلية مرسومة خصيصًا تستخدم في عنصر تحكم DataGridView. يشبه الرمز:

public class DataGridViewMyCustomColumn : DataGridViewColumn
{
    public DataGridViewMyCustomColumn() : base(new DataGridViewMyCustomCell())
    {
    }

يولد التحذير التالي:

CA2000: Microsoft.REILINIONING: في طريقة "DataGridViewMyCustomColumn.DatagridViewMyCustomColumn ()" System.Idisposable.dispose على كائن "DataGridViewMyCustomCell ()" قبل جميع المراجع خارج نطاقها.

أنا أفهم أنه يحذرني من DataGridViewMyCustomCell (أو فئة ترثها من) تنفذ الواجهة القابلة للتطبيق وينبغي استدعاء طريقة Dispose () لتنظيف أي موارد تطالب بها DataGridViewMyCustomCell عندما لم تعد.

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

سؤالي إذن ، هل الرمز بخير كما هو؟ أو ، كيف يمكن إعادة تمهيدها لحل التحذير؟ لا أريد قمع التحذير إلا إذا كان من المناسب حقًا القيام بذلك.

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

المحلول

إذا كنت تستخدم Visual Studio 2010 ، فسيتم كسر CA2000 تمامًا. قد يتم كسرها أيضًا في إصدارات أخرى من FXCOP (AKA Code Analysis) ، ولكن VS2010 هو الإصدارات الوحيدة التي يمكنني ضمها. تعطي قاعدة CodeBase تحذيرات CA2000 لكود مثل هذا ...

internal static class ConnectionManager 
{
    public static SqlConnection CreateConnection()
    {
         return new SqlConnection("our connection string");
    }
}

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

كان هذا قاعدة مفيدة ، ولكن الآن كل ما يمكنك فعله حقًا هو إيقاف تشغيله حتى يصلحها. وهو أمر مؤسف ، لأن الإيجابيات الفعلية (القليلة جدًا) هي الأشياء التي يجب إصلاحها.

نصائح أخرى

لا توجد طريقة آمنة وأنيقة لوجود مُنشئ بالسلاسل الجديدة IDisposable اعترض على المُنشئ الأساسي ، لأنه كما تلاحظ أنه لا يمكن لف المكالمة المُنشأة بالسلاسل في أي نوع من try finally الكتلة. هناك نهج آمن ، لكنه بالكاد أنيق: تحديد طريقة فائدة شيء مثل:

internal static TV storeAndReturn<TR,TV>(ref TR dest, TV value) where TV:TR
{ 
  dest = value; return value;
}

اجعل المُنشئ يبدو شيئًا مثل:

protected DataGridViewMyCustomColumn(ref IDisposable cleaner) : 
   base(storeAndReturn(ref cleaner, new DataGridViewMyCustomCell()))
{
}

الرمز الذي يحتاج إلى كائن جديد سيتعين عليه الاتصال بأسلوب مصنع ثابت عام من شأنه أن يستدعي المُنشئ المناسب ضمن أ try/finally كتلة من سوف يخترق الخط الرئيسي cleaner قبل الانتهاء مباشرة ومن finally سوف تتصل بلوك Dispose على cleaner إذا لم يكن فارغا. شريطة أن يحدد كل فئة فرعية طريقة مصنع مماثلة ، سيضمن هذا النهج الجديد IDisposable سيتم التخلص من الكائن حتى في حالة حدوث استثناء بين الوقت الذي يتم إنشاؤه فيه والوقت الذي يتعرض فيه الكائن المغلف لرمز العميل. النمط قبيح ، لكنني لست متأكدًا من أن أي نمط آخر أجمل من شأنه أن يضمن الصواب.

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