2010-08-23 14 views
6

Trong mã, nói rằng chúng ta có:Thu gom rác, chúng ta có nên dựa vào nó không?

using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString())) 
{ 
    cn.Open(); 

    // Set all previous settings to inactive 
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn)) 
    {        
     cmd.ExecuteNonQuery(); 
    } 

    cn.Close(); 
} 

Các cn.close không về mặt kỹ thuật được yêu cầu như thu gom rác thải sẽ chăm sóc của kết nối cho chúng ta.

Tuy nhiên, tôi luôn muốn đóng nó và không dựa vào việc thu gom rác thải. Điều này có tệ không? Một sự lãng phí thời gian? Hoặc được coi là thực hành tốt để không dựa vào tự động hóa?

Cảm ơn ý kiến ​​và ý kiến ​​của bạn trước. Tôi sẽ đánh dấu nó là wiki cộng đồng vì nó có thể chủ quan.

+7

vì bạn đang sử dụng câu lệnh 'using',' cn.Close() 'là hoàn toàn dư thừa. –

+4

trong ví dụ của bạn, đó là IDispose/using() dọn dẹp kết nối, chứ không phải GC.Thực hành tốt (cần thiết) để kiểm soát tuổi thọ của các tài nguyên như kết nối và tệp. GC chỉ nên dựa vào tài nguyên bộ nhớ. – tenfour

Trả lời

14

Bạn không bao giờ nên dựa vào GC cho việc này. Raymond Chen's blog article about this là một điểm khởi đầu tốt đẹp. Về cơ bản, nếu bạn không tự Close/Dispose kết nối của bạn, thì không có gì bảo đảm rằng nó sẽ xảy ra, bởi vì nếu không nó sẽ chỉ bao giờ xảy ra khi Dispose được gọi từ Finalizer mà có thể không bao giờ xảy ra:

Một chương trình được viết chính xác không thể giả định rằng finalizers sẽ bao giờ chạy tại bất kỳ điểm nào trước khi chương trình chấm dứt.

Có, trên thực tế, trình kết thúc cho kết nối của bạn có thể sẽ xảy ra, nhưng ngay cả khi đó, bạn đang giữ kết nối trực tiếp lâu hơn mức bạn thực sự cần. Điều này có thể tạo ra các vấn đề nếu cơ sở dữ liệu chỉ cho phép một số giới hạn các kết nối trực tiếp tại một thời điểm.

Điều bạn đang làm được coi là thực hành tốt: khi bạn đã hoàn tất với tài nguyên, hãy giải phóng chúng. Nếu một đối tượng là IDisposable, Dispose của đối tượng đó khi bạn có thể.

+0

+1. Về các kết nối cơ sở dữ liệu nói riêng, tôi bị cắn bởi mã của một đồng nghiệp cách đây vài tháng làm chính xác điều này. Ông chỉ để lại tất cả dọn dẹp cho finalizer, mà làm việc hoàn toàn tốt với databasses nhỏ nhưng "đột nhiên" bắt đầu thất bại trên cơ sở dữ liệu lớn do thời hạn trên finalizers trong quá trình xuất cảnh. Chi tiết ở đây: http://nitoprograms.blogspot.com/2009/08/finalizers-at-process-exit.html –

+0

Lưu ý rằng Chen tiếp tục nói rằng finalizers không được bảo đảm ** bao giờ ** được gọi, thậm chí khi ứng dụng thoát. – Tergiver

6

Trước hết - trong ví dụ của bạn, bạn đang sử dụng giao diện IDisposable, không liên quan gì đến GC. Về bản chất, mã của bạn biên dịch như sau:

SqlConnection cn = null; 
try 
{ 
    cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString()); 
    cn.Open(); 

    // Set all previous settings to inactive 
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn)) 
    { 
     cmd.ExecuteNonQuery(); 
    } 
    cn.Close(); 
} 
finally 
{ 
    if (cn != null) 
     cn.Dispose(); 
} 

Kể từ cn.Dispose()cn.Close() đều giống nhau trong trường hợp này - vâng, sau này là không cần thiết.

Bây giờ, nếu bạn muốn nói về GC, sau đó bạn muốn viết như thế này:

SqlCOnnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString()); 
    cn.Open(); 

    // Set all previous settings to inactive 
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn)) 
    { 
     cmd.ExecuteNonQuery(); 
    } 
    cn = null; // Or just leave scope without doing anything else with cn. 

Trong trường hợp này nó sẽ mất GC để đóng kết nối mở và gửi lại cho hồ bơi. Và trong trường hợp này, điều đó có nghĩa là bạn không thể dự đoán được khi nào điều đó xảy ra. Trong thực tế mã này sẽ (với xác suất cao) rò rỉ SqlConnections và sớm bạn sẽ chạy ra khỏi chúng (bạn sẽ nhận được một TimeoutException vì sẽ không có các kết nối có sẵn trong hồ bơi).

Vì vậy, vâng, ví dụ trên là cách chính xác. Bất cứ khi nào bạn sử dụng một số đối tượng thực hiện IDisposable, hãy bọc nó trong khối using. Và bạn không cần phải bận tâm với các .Close(), mặc dù nó không làm tổn thương một trong hai. Cá nhân tôi không viết nó mặc dù. Ít mã hơn, ít lộn xộn hơn.

Các vấn đề liên quan