2009-02-25 25 views
37

Nếu tôi viết một lớp trong C# mà thực hiện IDisposable, tại sao không phải là đủ đối với tôi chỉ đơn giản là thực hiệnĐiểm của việc ghi đè (bool disposing) trong .NET là gì?

public void Dispose(){ ... } 

để xử lý giải phóng bất kỳ nguồn lực không được quản lý?

protected virtual void Dispose(bool disposing){ ... } 

luôn cần thiết, đôi khi cần thiết, hoặc một cái gì đó khác hoàn toàn?

+0

Trong lớp học của tôi, tôi chỉ có tài nguyên không được quản lý cần dọn dẹp và tôi đang triển khai IDisposable với bảo vệ void void Dispose (bool disposing) như phân tích tĩnh buộc nó phải làm. Trong trường hợp của tôi, thông số "vứt bỏ" không có sử dụng vì tôi muốn Finalizer và Dispose làm điều tương tự. – AksharRoop

Trả lời

28

Không cần thiết. Nó là một phần của mẫu dùng một lần được đề nghị. Nếu bạn chưa đọc phần Hướng dẫn thiết kế khung về điều này (9.3 trong ấn bản đầu tiên, không có ấn bản thứ hai có ích) thì bạn nên làm như vậy. Try this link.

Tính năng này hữu ích để phân biệt giữa dọn dẹp một lần và thu gom rác thải cuối cùng-là-trashing-me.

Bạn không phải thực hiện theo cách đó nhưng bạn nên đọc kỹ và hiểu tại sao điều này được đề xuất trước khi giảm giá là không cần thiết.

+3

Liên kết tới "IDisposable: Những gì mẹ của bạn không bao giờ nói với bạn về Resource Deallocation" là quá xa dưới đây, vì vậy tôi sẽ lặp lại nó ở đây: http://www.codeproject.com/KB/dotnet/IDisposable.aspx –

+0

FYI the liên kết đầu tiên ở trên để bluebytesoftware hiện đã bị hỏng. – codenheim

+0

@mrjoltcola cảm ơn, cập nhật liên kết MSDN (nhưng chúng cũng có thể hơi muộn) –

3

Phương pháp bổ sung với bool disposing xuất phát từ hướng dẫn thiết kế khung ở đâu đó. Nó chỉ đơn giản là một khuôn mẫu để cho phép lớp của bạn có phương thức vứt bỏ có thể được gọi nhiều lần mà không cần ném một ngoại lệ. Nó không phải là hoàn toàn cần thiết. Về mặt kỹ thuật bạn có thể làm điều đó trong phương pháp vứt bỏ.

13

Có một chút thiên vị trong tài liệu MSFT về mẫu dùng một lần. Có hai lý do bạn nên thực hiện IDisposable: lĩnh vực

  1. Bạn đã có một loại mà thực hiện IDisposable
  2. Bạn đã có một finalizer.

Trường hợp 1 khá phổ biến ở hầu hết các mã. Trường hợp 2 là khá phổ biến trong mã mà Microsoft viết, họ là những người đã viết trình bao bọc được quản lý xung quanh các tài nguyên không được quản lý, những người cần hoàn tất. Nhưng phải rất hiếm trong mã của bạn. Sau khi tất cả, bạn đã có tất cả những NET tốt đẹp lớp học để làm công việc bẩn cho bạn. Bạn chỉ cần gọi phương thức Dispose() của họ.

Chỉ trường hợp 2 yêu cầu mẫu dùng một lần. Microsoft cần sử dụng nó rất nhiều. Bạn sẽ chỉ cần Dispose đơn giản() hầu hết thời gian.

+0

Trong lớp học của tôi, tôi chỉ có tài nguyên không được quản lý cần dọn dẹp và tôi đang triển khai IDisposable với bảo vệ void void Dispose (bool disposing) làm tĩnh phân tích buộc nó phải làm. Trong trường hợp của tôi, thông số "vứt bỏ" không có sử dụng vì tôi muốn Finalizer và Dispose làm điều tương tự. – AksharRoop

+0

Không chắc chắn ý kiến ​​đó là gì để truyền tải. Bạn có thể làm sai, sử dụng các lớp trình bao bọc SafeHandle và/hoặc SafeBuffer. Kết luận quan trọng là tốt đẹp. Quay lại bullet 1. –

+0

Ok, vậy câu hỏi ban đầu của tôi là những gì khác nhau Vứt bỏ (bool disposing) nên làm gì khi giá trị là true và value là false. Xử lý thông số được sử dụng để làm gì? – AksharRoop

41

Mẫu đầy đủ bao gồm trình hoàn thiện, giới thiệu phương pháp ảo mới và "niêm phong" phương pháp vứt bỏ ban đầu là mục đích rất chung chung, bao gồm tất cả các cơ sở.

Trừ khi bạn có xử lý trực tiếp về tài nguyên không được quản lý (mà phải được almostnever), bạn không cần một finalizer.

Nếu bạn đóng dấu lớp học của bạn (và quan điểm của tôi về niêm phong các lớp học bất cứ khi nào có thể có thể được biết đến bây giờ - design for inheritance or prohibit it) không có điểm trong việc giới thiệu một phương pháp ảo.

Tôi không thể nhớ lần cuối tôi triển khai IDisposable theo cách "phức tạp" khi thực hiện theo cách rõ ràng nhất, ví dụ:

public void Dispose() 
{ 
    somethingElse.Dispose(); 
} 

Một điều cần lưu ý là nếu bạn đang đi cho mã thực sự mạnh mẽ, bạn nên hãy chắc chắn rằng bạn không cố gắng làm bất cứ điều gì sau khi bạn đã được xử lý, và ném ObjectDisposedException nơi thích hợp . Đó là lời khuyên tốt cho các thư viện lớp sẽ được các nhà phát triển sử dụng trên toàn thế giới, nhưng nó có rất nhiều công việc để đạt được rất ít nếu đây chỉ là một lớp được sử dụng trong không gian làm việc của riêng bạn.

+0

Giải thích tuyệt vời - và giảm nhẹ! –

+0

FYI, liên kết của bạn đến bluebyte bị hỏng –

+0

@HamishSmith: Đã sửa lỗi, cảm ơn. (Blog đã di chuyển.) –

5

Ngoài các câu trả lời tuyệt vời khác, bạn có thể muốn kiểm tra những bài viết này:

+2

Bài viết đầu tiên vẫn bao gồm thuộc tính 'xử lý' trong trường hợp vứt bỏ đơn giản, đó là vô nghĩa. Trường hợp thực sự đơn giản là những gì Jon đưa vào ví dụ của mình, với sự bổ sung có thể có của từ khóa 'ảo'. – piers7

1

Chỉ cần để mở rộng vào những gì người khác có cho biết: không chỉ là bạn không cần 'xử lý phức tạp', đó là bạn thực sự không muốn nó, cho hiệu suất rea con trai.

Nếu bạn đi tuyến đường 'vứt bỏ phức tạp' và triển khai finalizer, và sau đó quên bỏ đối tượng của bạn một cách rõ ràng, đối tượng của bạn (và bất kỳ thứ gì nó tham chiếu) sẽ tồn tại thêm thế hệ GC trước khi nó thực sự được xử lý (vì nó có để treo xung quanh một lần nữa cho CLR để gọi finalizer). Điều này chỉ gây ra nhiều áp lực bộ nhớ mà bạn không cần. Ngoài ra, việc gọi trình hoàn thiện trên toàn bộ đống đối tượng có chi phí không đáng kể.

Vì vậy, tránh, trừ khi bạn (hoặc các loại có nguồn gốc của bạn) có tài nguyên không được quản lý. Ồ, và trong khi chúng tôi đang ở trong khu vực: các phương pháp trong lớp học của bạn xử lý các sự kiện từ những người khác phải là 'an toàn' khi đối mặt với việc được triệu tập sau khi lớp học của bạn đã được xử lý. Đơn giản nhất là chỉ thực hiện một no-op nếu lớp được xử lý. Xem http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx

1

Một điều mà nó mang lại cho bạn là khả năng thực hiện công việc trong Vứt bỏ() không liên quan đến việc hoàn tất và vẫn dọn sạch tài nguyên không được quản lý.

Làm bất kỳ điều gì cho đối tượng được quản lý khác với 'chính mình' trong trình hoàn thành là vô cùng ... không thể đoán trước. Hầu hết điều này là do thực tế là finalizers của bạn sẽ được gọi trong giai đoạn 2 tắt AppDomain của bạn một cách không xác định - vì vậy khi finalizer của bạn được gọi, nó rất có khả năng các đối tượng mà bạn vẫn có tài liệu tham khảo đã được hoàn thành.

Gửi cả cuộc gọi Dispose và finalizer đến cùng một phương thức cho phép bạn chia sẻ mã shutdown của mình, trong khi tham số boolean cho phép bạn bỏ qua dọn dẹp được quản lý nếu có.

Ngoài ra, ảo-ness của phương pháp cung cấp một cách dễ dàng cho người thừa kế để thêm mã dọn dẹp của riêng họ, với ít nguy cơ vô tình không gọi điện thoại của bạn.

1

Nếu một lớp thực hiện IDisposable.Dispose() và lớp dẫn xuất cần thêm logic bổ sung, lớp đó phải hiển thị một số loại phương thức Dispose mà lớp dẫn xuất có thể liên kết. Vì một số lớp có thể triển khai IDisposable.Dispose() mà không có phương thức công khai Dispose(), nên có phương pháp ảo là protected trong tất cả các lần triển khai IDisposable bất kể phương thức nào có phương thức công khai Dispose hay không.Trong hầu hết các trường hợp, đối số bool không thực sự có ý nghĩa nhưng nên được coi là đối số giả để làm cho số protected virtual Dispose(bool) có chữ ký khác với số có thể là hoặc có thể không công khai Dispose().

Các lớp không sử dụng số protected virtual Dispose(bool) sẽ yêu cầu các lớp dẫn xuất để xử lý logic dọn dẹp của chúng theo cách khác với quy ước. Một số ngôn ngữ như C++/CLI chỉ được trang bị để mở rộng việc triển khai IDisposable theo quy ước đó có thể không thể lấy được các lớp từ việc triển khai không chuẩn.

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