Đã đọc các chủ đề Là SqlCommand. Có đủ không? và Đóng và loại bỏ một dịch vụ WCF Tôi đang tự hỏi đối với các lớp như SqlConnection hoặc một trong một số lớp kế thừa từ lớp Stream có vấn đề gì không nếu tôi đóng Vứt bỏ thay vì Đóng?
Đã đọc các chủ đề Là SqlCommand. Có đủ không? và Đóng và loại bỏ một dịch vụ WCF Tôi đang tự hỏi đối với các lớp như SqlConnection hoặc một trong một số lớp kế thừa từ lớp Stream có vấn đề gì không nếu tôi đóng Vứt bỏ thay vì Đóng?
Câu trả lời:
Theo hướng dẫn của Microsoft, đây là một cách thực hành tốt để cung cấp Closephương pháp phù hợp. Dưới đây là một trích dẫn từ hướng dẫn thiết kế khung
Xem xét việc cung cấp phương pháp
Close(), ngoài việcDispose(), nếu đóng là thuật ngữ tiêu chuẩn trong khu vực. Khi làm như vậy, điều quan trọng là bạn phảiClosethực hiện giống hệtDispose...
Trong hầu hết các trường hợp Closevà Disposephương pháp là tương đương. Sự khác biệt chính giữa Closevà Disposetrong trường hợp SqlConnectionObjectlà:
Một ứng dụng có thể gọi
Closenhiều hơn một lần. Không có ngoại lệ được tạo ra.Nếu bạn gọi trạng thái đối tượng
Disposephương thứcSqlConnectionsẽ được thiết lập lại. Nếu bạn cố gắng gọi bất kỳ phương thức nào trênSqlConnectionđối tượng bị loại bỏ , bạn sẽ nhận được ngoại lệ.
Mà nói:
Dispose.Closephương thức.con.Open() con.Close(); 2 con.Open(); // reuse 3. con.Dispose(); // use one time con.Open(); // error
Như thường lệ, câu trả lời là: nó phụ thuộc. Các lớp khác nhau thực hiện IDisposabletheo những cách khác nhau và tùy thuộc vào bạn để thực hiện nghiên cứu cần thiết.
Theo như SqlClientđi, thực hành được khuyến nghị là làm như sau:
using (SqlConnection conn = /* Create new instance using your favorite method */)
{
conn.Open();
using (SqlCommand command = /* Create new instance using your favorite method */)
{
// Do work
}
conn.Close(); // Optional
}
Bạn nên gọi Dispose(hoặc Close*) trên kết nối! Đừng không chờ cho thu gom rác để làm sạch kết nối của bạn, điều này sẽ buộc các kết nối trong hồ bơi cho đến khi chu kỳ GC tiếp theo (ít nhất). Nếu bạn gọi Dispose, không cần thiết phải gọi Close, và vì usingcấu trúc giúp dễ dàng xử lý Disposechính xác, nên thực sự không có lý do gì để gọi Close.
Các kết nối được tự động gộp lại và gọi Dispose/ Closetrên kết nối không đóng kết nối vật lý (trong trường hợp bình thường). Đừng cố gắng thực hiện tổng hợp của riêng bạn. SqlClientthực hiện dọn dẹp kết nối khi nó được truy xuất từ nhóm (như khôi phục bối cảnh cơ sở dữ liệu và các tùy chọn kết nối).
* nếu bạn đang gọi Close, hãy đảm bảo thực hiện theo cách an toàn ngoại lệ (nghĩa là trong một lần bắt hoặc cuối cùng là chặn).
conn.Close(); // OptionalNó không phải là tùy chọn. Nó dư thừa và không cần thiết. Bạn đang xử lý đối tượng hai lần và điều này sẽ được đánh dấu là cảnh báo bởi một số công cụ phân tích mã.
using (var x = ..) { x.Dispose(); }, trong trường hợp đó xthực sự là "xử lý hai lần".
Bạn cần gọi Dispose ()!
Vứt bỏ () là để nhà phát triển gọi, Garbage Collector gọi Finalize (). Nếu bạn không gọi Dispose () trên các đối tượng của mình thì mọi tài nguyên không được quản lý mà chúng sử dụng sẽ không được xử lý cho đến khi người thu gom rác xuất hiện và gọi hoàn thiện chúng (và ai biết khi nào điều đó sẽ xảy ra).
Kịch bản này được gọi là Quyết định không xác định và là một cái bẫy phổ biến cho các nhà phát triển .net. Nếu bạn đang làm việc với các đối tượng triển khai IDis Dùng thì hãy gọi Dispose () trên chúng!
http://www.ondotnet.com/pub/a/oreilly/dotnet/news/programmingCsharp_0801.html?page=last
Mặc dù có thể có nhiều trường hợp (như trên SqlConnection) khi bạn gọi Disponse () trên một số đối tượng và nó chỉ đơn giản gọi Close () trên kết nối của nó hoặc đóng một tay cầm tệp, gần như luôn luôn là lựa chọn tốt nhất của bạn để gọi Dispose ()! trừ khi bạn có kế hoạch tái sử dụng đối tượng trong tương lai rất gần.
Dispose.
Dispose() nếu bạn không sử dụng using()với một lớp thực hiện IDisposable. Nếu lớp được gọi là thực hiện IDis Dùng một lần và bạn đã kết thúc việc sử dụng nó trên trang bên trong using(), thì bạn có thể loại bỏ bằng Dispose()(ý định chơi chữ, vì vậy hãy bắn tôi). Close()Tuy nhiên, việc sử dụng được khuyến nghị với bất kỳ thứ gì sử dụng rõ ràng Open(), AFAIK.
Closekết nối, Postgres sẽ tự động đặt định danh kết nối thành null. Từ đó trở đi, người ta không thể Disposenhận dạng kết nối sql đã được đặt thành null.
Đối với SqlConnection, từ quan điểm của chính kết nối, chúng là tương đương. Theo Reflector, Dispose()các cuộc gọiClose() cũng như thực hiện một vài thao tác giải phóng bộ nhớ bổ sung - chủ yếu bằng cách đặt các thành viên bằng null.
Đối với Stream, chúng thực sự là tương đương. Stream.Dispose()chỉ cần gọi Đóng ().
Component đó dường như không làm gì để thử và gọiClose() . Tôi không thể thấy bất cứ nơi nào trong DBConnectionhoặc SqlConnectioncó liên quan đến một trong những thông báo đó. Tuy nhiên, nó có một cái riêng DisposeMe()không được tham chiếu ở bất cứ đâu .
Lời khuyên nhanh chóng này sẽ trở thành một câu trả lời dài. Lấy làm tiếc.
Như ông trùm đã chỉ ra trong câu trả lời hay của mình, gọi Dispose() là một thực hành lập trình tuyệt vời. Điều này là do phương pháp này được cho là "tập hợp lại" tất cả các giải phóng tài nguyên cần thiết để không có tài nguyên mở không cần thiết. Ví dụ, nếu bạn đã viết một số văn bản vào một tệp và không đóng tệp (giải phóng tài nguyên), nó sẽ vẫn mở và không ai khác có thể ghi vào đó cho đến khi GC xuất hiện và làm những gì bạn nên có làm xong.
Bây giờ, trong một số trường hợp, sẽ có các phương thức "hoàn thiện" cụ thể hơn cho lớp bạn đang xử lý, như StreamWriter.Close(), ghi đè TextWriter.Close(). Thật vậy, chúng thường phù hợp hơn với tình huống: Close()ví dụ, một StreamWriter , tuôn ra luồng và bộ mã hóa cơ bản trước khi Dispose()ing đối tượng! Mát mẻ!
Tuy nhiên, duyệt MSDN, bạn sẽ thấy rằng ngay cả Microsoft đôi khi cũng bị nhầm lẫn bởi vô số các công cụ đóng và xử lý. Ví dụ, trong trang web này , trong một số ví dụ Close()được gọi trước ẩn Dispose()(xem sử dụng câu lệnh nếu bạn không hiểu tại sao nó ẩn) và đặc biệt là trong một ví dụ họ không bận tâm. Tại sao lại như vậy? Tôi cũng đã bối rối.
Lý do tôi tìm ra (và, tôi nhấn mạnh, đây là nghiên cứu ban đầu và tôi chắc chắn có thể mất danh tiếng nếu tôi sai) là điều đó Close()có thể thất bại, mang lại một ngoại lệ trong khi để tài nguyên mở, trong khi Dispose()chắc chắn sẽ giải phóng chúng . Đó là lý do tại sao một Dispose()luôn luôn phải bảo vệ một Close()cuộc gọi (xin lỗi vì chơi chữ).
MyResource r = new MyResource();
try {
r.Write(new Whatever());
r.Close()
finally {
r.Dispose();
}
Và vâng, tôi đoán Microsoft đã trượt vào một ví dụ đó. Có lẽ dấu thời gian đó sẽ không bao giờ bị xóa vào tập tin.
Tôi đang sửa mã cũ vào ngày mai.
Chỉnh sửa: xin lỗi Brannon, tôi không thể nhận xét về câu trả lời của bạn, nhưng bạn có chắc chắn nên gọi Close()cho một finallykhối không? Tôi đoán một ngoại lệ từ đó có thể phá hỏng phần còn lại của khối, có khả năng sẽ chứa mã dọn dẹp quan trọng.
Trả lời Brannon's: tuyệt vời, chỉ cần đừng quên gọi Close()khi thực sự cần thiết (ví dụ: khi xử lý các luồng - không biết nhiều về các kết nối SQL trong .NET).
Đánh máy chữ sang iDis Dùng một lần và gọi vứt bỏ nó. Điều đó sẽ gọi bất kỳ phương thức nào được cấu hình là thực hiện "iDis Dùng một lần.", Bất kể hàm được đặt tên là gì.
IDisposable.Dispose, nhưng điều đó không có nghĩa đó là tên. Lưu ý rằng trong vb.net, có thể có một chức năng được liên kết với nhiều thành viên giao diện với các tên không cần liên quan đến chức năng đó.
using (myObj as IDisposable)
Nói chung, chúng tôi đang phải đối mặt với vấn đề trong Đóng (), Hủy bỏ () và Loại bỏ () nhưng để tôi cho bạn biết sự khác biệt giữa chúng.
1) TRẢ LỜI: - Tôi sẽ không đề xuất sử dụng điều này bởi vì khi hủy bỏ được gọi, máy khách sẽ xóa kết nối mà không báo cho máy chủ để máy chủ sẽ đợi trong một khoảng thời gian (khoảng 1 phút). Nếu bạn có yêu cầu số lượng lớn thì bạn không thể sử dụng hủy bỏ () vì điều đó có thể khiến hết thời gian cho nhóm kết nối bị giới hạn của bạn.
2) Đóng: - Đóng là cách rất tốt để đóng kết nối vì khi đóng kết nối, nó sẽ gọi máy chủ và xác nhận máy chủ cũng đóng bên đó.
Ở đây, một điều nữa để xem xét. Trong một số trường hợp, nếu lỗi tạo ra thì đó không phải là cách tốt để viết mã cuối cùng là kết nối đó. Đóng () vì tại thời điểm đó Trạng thái giao tiếp sẽ bị lỗi.
3) Loại bỏ: - Đây là một loại đóng nhưng sau khi đóng kết nối, bạn không thể mở lại.
Vì vậy, hãy thử cách này,
private void CloseConnection(Client client)
{
if (client != null && client.State == CommunicationState.Opened)
{
client.Close();
}
else
{
client.Abort();
}
}
client != nulllà không chính xác / gây hiểu lầm bởi vì nó không bảo vệ tất cả các công dụng. Ngoài ra, tôi không chắc làm thế nào mã có thể chuyển sang trạng thái "kết nối này không được mở và nên được đóng lại".