หลายๆ คนคิดว่าเมธอด Dispose() ถูกเรียกเป็นการภายในในเมธอด Close() ดังนั้นจึงไม่มีความแตกต่างที่สำคัญ! ที่จริงแล้วมุมมองนี้ไม่ค่อยแม่นยำนัก
สำหรับบางคลาส เป็นความจริงที่ว่าไม่มีความแตกต่างที่สำคัญระหว่าง Close() และ Dispose() แต่สำหรับบางคลาสก็ไม่เป็นเช่นนั้น!
ก่อนอื่น เรามาดูความแตกต่างระหว่างเมธอด Close() และเมธอด Dispose() ของ SqlConnection ที่เราใช้บ่อยที่สุด:
วิธีการ Dispose() ของคลาส SqlConnection นั้นสืบทอดมาจากคลาส Component ซอร์สโค้ดจะเป็นดังนี้:
โมฆะสาธารณะกำจัด () {
Dispose(true); //เรียกการโอเวอร์โหลดของ Dispose ด้วยพารามิเตอร์
GC.SuppressFinalize(this); //ขอให้ระบบไม่เรียกตัวปิดท้ายของอ็อบเจ็กต์ที่ระบุ
-
การกำจัดโมฆะเสมือนที่ได้รับการป้องกัน (การกำจัดบูล) {
ถ้า (ทิ้ง) {
ล็อค (นี้) {
ถ้า (ไซต์ != null && site.Container != null) {
site.Container.Remove (นี้);
-
ถ้า (เหตุการณ์ != null) {
ตัวจัดการ EventHandler = (EventHandler) เหตุการณ์ [EventDisposed];
ถ้า (ตัวจัดการ != null) ตัวจัดการ (นี่คือ EventArgs.Empty);
-
-
-
-
คำอธิบายของวิธีการ Close() ของคลาส SqlConnection ใน MSDN มีดังต่อไปนี้:
ปิดการเชื่อมต่อกับฐานข้อมูล นี่เป็นวิธีที่แนะนำในการปิดการเชื่อมต่อที่เปิดอยู่ ถ้า SqlConnection อยู่นอกขอบเขต ก็จะไม่ถูกปิด เพราะ
ดังนั้น การเชื่อมต่อจะต้องปิดอย่างชัดเจน โดยการเรียกปิดหรือกำจัด ปิดและกำจัดมีฟังก์ชันการทำงานที่เทียบเท่ากัน หากค่าพูลการเชื่อมต่อ
การรวมกลุ่ม หากตั้งค่าเป็นจริงหรือใช่ การเชื่อมต่อพื้นฐานจะถูกส่งกลับไปยังพูลการเชื่อมต่อ ในทางกลับกัน หากตั้งค่า Pooling เป็นเท็จหรือไม่ใช่
การเชื่อมต่อพื้นฐานไปยังเซิร์ฟเวอร์ถูกปิด
จากคำอธิบาย ดูเหมือนว่าเมธอด Close() และเมธอด Dispose() จะคล้ายกัน จริงๆ แล้วพวกมันจะเทียบเท่ากันในฟังก์ชันการปิดการเชื่อมต่อเท่านั้น เรามาดูกันที่ Close
() รหัสที่มาวิธีการ:
แทนที่โมฆะสาธารณะปิด () {
IntPtr hscp;
Bid.ScopeEnter(ออก hscp, "<sc.SqlConnection.Close|API> %d#" , ObjectID);
พยายาม {
สถิติ SqlStatistics = null;
RuntimeHelpers.PrepareConstrainedRegions();
พยายาม {
#ถ้า DEBUG
วัตถุ InitialReliabilitySlotValue = Thread.GetData (TdsParser.ReliabilitySlot);
RuntimeHelpers.PrepareConstrainedRegions();
พยายาม {
Thread.SetData(TdsParser.ReliabilitySlot จริง);
#endif //DEBUG
สถิติ = SqlStatistics.StartTimer (สถิติ);
// การล็อคที่นี่คือการป้องกัน command.cancel / Connection.close
สภาพการแข่งขัน
// SqlInternalConnectionTds ถูกตั้งค่าเป็น OpenBusy ระหว่างการปิด ในกรณีนี้
เกิดอะไรขึ้นนักแสดงด้านล่างจะล้มเหลวและ
// คำสั่งนี้จะไม่สามารถยกเลิกได้อีกต่อไป อาจเป็นที่ต้องการ
สามารถยกเลิกการดำเนินการปิดได้แต่เป็นเช่นนี้
// อยู่นอกขอบเขตของ Whidbey RTM ดู (SqlCommand::Cancel) สำหรับสิ่งอื่น
ล็อค.
ล็อค (การเชื่อมต่อภายใน) {
InnerConnection.CloseConnection (นี่คือ ConnectionFactory);
-
// ไม่ต้องการ GC.KeepAlive(สิ่งนี้) เนื่องจาก OnStateChange
ถ้า (null != สถิติ) {
ADP.TimerCurrent (ออก _statistics._closeTimestamp);
-
#ถ้า DEBUG
-
ในที่สุด {
Thread.SetData (TdsParser.ReliabilitySlot, defaultReliabilitySlotValue);
-
#endif //DEBUG
-
จับ (System.OutOfMemoryException e) {
ยกเลิก(e);
โยน;
-
จับ (System.StackOverflowException e) {
ยกเลิก(e);
โยน;
-
จับ (System.Threading.ThreadAbortException e) {
ยกเลิก(e);
โยน;
-
ในที่สุด {
SqlStatistics.StopTimer (สถิติ);
-
-
ในที่สุด {
SqlDebugContext sdc = _sdc;
_sdc = โมฆะ;
Bid.ScopeLeave(อ้างอิง hscp);
ถ้า (sdc != null) {
sdc.ทิ้ง();
-
-
-
คุณจะเห็นว่าเมธอด Close() ไม่ได้เรียกใช้เมธอด Dispose() แม้ว่าจะมีบรรทัดของ sdc.Dispose(); แต่สิ่งนี้จะเผยแพร่ SqlDebugContext เท่านั้น
อินสแตนซ์ไม่เกี่ยวข้องกับเมธอด SqlConnection.Dispose()!
แล้วความแตกต่างคืออะไร?
เมธอด Close() จะปิดการเชื่อมต่อเท่านั้น จากนั้นการเชื่อมต่อจะถูกจัดเก็บไว้ในพูลการเชื่อมต่อ ดังนั้นหลังจากเรียกเมธอด Close() แล้ว คุณยังคงสามารถส่งผ่านได้
เมธอด Open() เพื่อเปิดการเชื่อมต่อ และหลังจากเรียกใช้เมธอด Dispose() แล้ว การเชื่อมต่อจะไม่สามารถใช้ได้อีกต่อไป!
ข้อแตกต่างที่สำคัญอีกประการหนึ่งก็คือ เมื่อเมธอด Close() ไม่เรียก GC.SuppressFinalize(this) ผลที่ตามมาโดยตรงของสิ่งนี้ก็คือขยะ
จำเป็นต้องมีการดำเนินการยุติในระหว่างการรีไซเคิล ซึ่งจะทำให้ "อายุรุ่น" ของอินสแตนซ์นี้เพิ่มขึ้น ซึ่งจะทำให้เวลาในการรีไซเคิลของวัตถุนี้ล่าช้าออกไปอย่างมาก!
สำหรับคลาส SqlConnection หากคุณต้องการใช้การเชื่อมต่อนี้ในอนาคต คุณสามารถใช้เมธอด Close() เพื่อปิดการเชื่อมต่อชั่วคราวได้
หากต้องการใช้การเชื่อมต่อนี้ ก่อนอื่นคุณสามารถใช้เมธอด Dispose() เพื่อเผยแพร่ทรัพยากรได้ แน่นอนว่าคุณสามารถใช้คีย์เวิร์ดที่ใช้เพื่อทำให้กระบวนการนี้ง่ายขึ้น
ฉันไม่พบซอร์สโค้ดของคลาส OleDbConnection และคลาส OdbcConnection แต่ควรจะคล้ายกับคลาส SqlConnection!
ลองดูคลาสที่ใช้กันทั่วไปและดูความแตกต่างระหว่างเมธอด Close() และเมธอด Dispose() ของคลาส FileStream:
วิธีการ Close() ของคลาส FileStream นั้นสืบทอดมาจากคลาส Stream ซอร์สโค้ดจะเป็นดังนี้:
โมฆะเสมือนสาธารณะปิด ()
-
กำจัด(จริง);
GC.SuppressFinalize(นี่);
-
วิธีการ Dispose() ของคลาส FileStream นั้นสืบทอดมาจากคลาส Stream ซอร์สโค้ดจะเป็นดังนี้:
โมฆะสาธารณะกำจัด ()
-
ปิด();
-
เป็นการนำโหมด Dispose มาตรฐานไปใช้ เมธอด Close() เรียกเมธอด Dispose พร้อมพารามิเตอร์ แล้วเรียก GC.SuppressFinalize
(สิ่งนี้) ร้องขอให้ระบบไม่เรียกตัวสรุปของวัตถุที่ระบุ เมธอด Dispose() เรียกเมธอด Close() โดยตรง!
สำหรับคลาส FileStream ไม่มีความแตกต่างระหว่างเมธอด Close() และเมธอด Dispose()!