يعتقد الكثير من الناس أن طريقة Dispose() يتم استدعاؤها داخليًا في طريقة Close()، لذلك لا يوجد فرق جوهري! في الواقع، هذا الرأي ليس دقيقًا جدًا.
بالنسبة لبعض الفئات، صحيح أنه لا يوجد فرق جوهري بين Close() و Dispose()، ولكن بالنسبة لبعض الفئات هذا ليس هو الحال!
أولاً، دعونا نلقي نظرة على الفرق بين طريقة Close() وطريقة Dispose() الخاصة بـ SqlConnection التي نستخدمها غالبًا:
يتم توريث أسلوب Dispose() الخاص بفئة SqlConnection من فئة Component، ويكون كود المصدر كما يلي:
التخلص من الفراغ العام () {
التخلص (صحيح)؛ // استدعاء التحميل الزائد للتخلص من المعلمات
GC.SuppressFinalize(this); //اطلب من النظام عدم استدعاء أداة الإنهاء للكائن المحدد.
}
التخلص من الفراغ الظاهري المحمي (التخلص المنطقي) {
إذا (التخلص) {
قفل (هذا) {
إذا (الموقع != فارغ && site.Container != فارغ) {
site.Container.Remove(this);
}
إذا (الأحداث! = فارغة) {
EventHandler Handler = (EventHandler)events[EventDispose];
if (handler != null) Handler(this, EventArgs.Empty);
}
}
}
}
وصف طريقة Close() لفئة SqlConnection في MSDN كما يلي:
قم بإغلاق الاتصال بقاعدة البيانات. هذه هي الطريقة المفضلة لإغلاق أي اتصال مفتوح. إذا خرج SqlConnection عن النطاق، فلن يتم إغلاقه. لأن
لذلك، يجب إغلاق الاتصال بشكل صريح عن طريق استدعاء Close أو Dispose. الإغلاق والتخلص متساويان وظيفيًا. إذا كانت قيمة تجمع الاتصال
التجميع إذا تم التعيين على "صحيح" أو "نعم"، فسيتم إرجاع الاتصال الأساسي إلى تجمع الاتصالات. من ناحية أخرى، إذا تم تعيين التجميع على خطأ أو لا، إذن
تم إغلاق الاتصال الأساسي بالخادم.
من الوصف، يبدو أن طريقة Close () وطريقة Dispose () متشابهتان في الواقع، فهي متكافئة فقط في وظيفة إغلاق الاتصال.
() كود مصدر الطريقة:
تجاوز الفراغ العام Close() {
IntPtr hscp;
Bid.ScopeEnter(out hscp, "<sc.SqlConnection.Close|API> %d#" , ObjectID);
يحاول {
إحصائيات SqlStatistics = null;
RuntimeHelpers.PrepareConstrainedRegions();
يحاول {
#إذا تم التصحيح
الكائن الأوليReliabilitySlotValue = Thread.GetData(TdsParser.ReliabilitySlot);
RuntimeHelpers.PrepareConstrainedRegions();
يحاول {
Thread.SetData(TdsParser.ReliabilitySlot, true);
#endif //DEBUG
Statistics = SqlStatistics.StartTimer(Statistics);
// القفل هنا هو للحماية من الأمر Command.cancel /connection.Close
حالة السباق
// يتم تعيين SqlInternalConnectionTds على OpenBusy أثناء الإغلاق، بمجرد ذلك
ما يحدث سوف يفشل طاقم الممثلين أدناه و
// لن يكون الأمر قابلاً للإلغاء بعد الآن، وقد يكون من المرغوب فيه أن يكون كذلك
قادرة على إلغاء عملية الإغلاق، ولكن هذا هو
// خارج نطاق Whidbey RTM، راجع (SqlCommand::Cancel) للآخرين
قفل.
قفل (اتصال داخلي) {
InnerConnection.CloseConnection(this, ConnectionFactory);
}
// لا يتطلب GC.KeepAlive(this) بسبب OnStateChange
إذا (فارغة!= إحصائيات) {
ADP.TimerCurrent(out _statistics._ CloseTimestamp);
}
#إذا تم التصحيح
}
أخيراً {
Thread.SetData(TdsParser.ReliabilitySlot, initialReliabilitySlotValue);
}
#endif //DEBUG
}
التقاط (System.OutOfMemoryException e) {
إحباط (ه)؛
يرمي؛
}
قبض على (System.StackOverflowException ه) {
إحباط (ه)؛
يرمي؛
}
قبض على (System.Threading.ThreadAbortException ه) {
إحباط (ه)؛
يرمي؛
}
أخيراً {
SqlStatistics.StopTimer(statistics);
}
}
أخيراً {
SqlDebugContext sdc = _sdc;
_sdc = null;
Bid.ScopeLeave(ref hscp);
إذا (سدك!= فارغة) {
sdc.Dispose();
}
}
}
يمكنك أن ترى أن طريقة Close() لا تستدعي طريقة Dispose() على الرغم من وجود سطر من sdc.Dispose();، إلا أن هذا يؤدي إلى تحرير SqlDebugContext فقط.
المثيل، لا علاقة له بطريقة SqlConnection.Dispose()!
إذن ما الفرق؟
تقوم طريقة Close() بإغلاق الاتصال فقط، ثم يتم تخزين الاتصال في تجمع الاتصالات، لذلك بعد استدعاء طريقة Close()، لا يزال بإمكانك المرور
Open() لفتح الاتصال وبعد استدعاء طريقة Dispose()، لم يعد من الممكن استخدام الاتصال!
هناك اختلاف مهم آخر وهو أنه عندما لا تستدعي طريقة Close() GC.SuppressFinalize(this);، فإن النتيجة المباشرة لذلك هي القمامة.
عمليات الإنهاء مطلوبة أثناء إعادة التدوير، مما سيؤدي إلى زيادة "عمر الجيل" لهذا المثيل، وبالتالي تأخير وقت إعادة التدوير لهذا الكائن بشكل كبير!
بالنسبة لفئة SqlConnection، إذا كنت بحاجة إلى استخدام هذا الاتصال في المستقبل، فيمكنك استخدام طريقة Close() لإغلاق الاتصال مؤقتًا.
لاستخدام هذا الاتصال، يمكنك أولاً استخدام طريقة Dispose() لتحرير الموارد. بالطبع، يمكنك استخدام الكلمة الأساسية use لتبسيط هذه العملية.
لم أجد الكود المصدري لفئة OleDbConnection وفئة OdbcConnection، لكن يجب أن تكون مشابهة لفئة SqlConnection!
دعونا نلقي نظرة على فئة شائعة الاستخدام ونرى الفرق بين طريقة Close() وطريقة Dispose() لفئة FileStream:
يتم توريث طريقة Close () لفئة FileStream من فئة Stream. كود المصدر كما يلي:
إغلاق الفراغ الظاهري العام ()
{
التخلص(صحيح);
GC.SuppressFinalize(this);
}
طريقة Dispose() لفئة FileStream موروثة من فئة Stream. كود المصدر كما يلي:
التخلص من الفراغ العام ()
{
يغلق()؛
}
إنه تطبيق لوضع التخلص القياسي. تستدعي الطريقة Close() طريقة التخلص مع المعلمات، ثم تستدعي GC.SuppressFinalize.
(هذا)؛ يطلب من النظام عدم استدعاء المُنهي للكائن المحدد. تستدعي طريقة Dispose() طريقة Close() مباشرة!
بالنسبة لفئة FileStream، لا يوجد فرق بين طريقة Close() وطريقة Dispose()!