Viết hàm hủy của riêng bạn (còn gọi là finalizer) là sai trong 99,99% của tất cả các trường hợp. Chúng cần thiết để đảm bảo rằng lớp của bạn phát hành một tài nguyên hệ điều hành không được khung .NET tự động quản lý và không được người dùng lớp của bạn phát hành đúng cách.
Điều này bắt đầu bằng việc phải phân bổ tài nguyên hệ điều hành trước tiên trong mã của riêng bạn. Điều đó luôn đòi hỏi một số loại P/Invoke. Đây là rất hiếm khi cần thiết, đó là công việc của các lập trình viên .NET làm việc tại Microsoft để chăm sóc điều đó.
Họ đã làm trong trường hợp của StreamWriter. Thông qua một số lớp, nó là một wrapper xung quanh một tập tin xử lý, tạo ra với CreateFile(). Lớp tạo ra tay cầm cũng là lớp có trách nhiệm viết trình hoàn thiện. Mã của Microsoft, không phải của bạn.
Lớp như vậy luôn triển khai IDisposable, cho người dùng của lớp cơ hội giải phóng tài nguyên khi nó được thực hiện với nó, thay vì đợi người hoàn thiện hoàn thành công việc. StreamWriter thực hiện IDisposable.
Tất nhiên, đối tượng StreamWriter của bạn là chi tiết triển khai cá nhân của lớp học của bạn. Bạn không biết khi nào người dùng được thực hiện với lớp Logger của bạn, bạn không thể gọi StreamWriter.Dispose() tự động. Bạn cần giúp đỡ.
Nhận trợ giúp đó bằng cách tự mình triển khai IDisposable.Người dùng của lớp học của bạn bây giờ có thể gọi Dispose hoặc sử dụng câu lệnh sử dụng, giống như cô làm với bất kỳ của các lớp khung:
class Logger : IDisposable {
private StreamWriter sw;
public void Dispose() {
sw.Dispose(); // Or sw.Close(), same thing
}
// etc...
}
Vâng, đó là những gì bạn nên làm trong 99,9% của tất cả các trường hợp. Nhưng không phải ở đây. Với nguy cơ làm bạn bối rối: nếu bạn triển khai IDisposable, cũng phải có cơ hội hợp lý để người dùng của lớp của bạn gọi phương thức Dispose() của nó. Đó thường không phải là một vấn đề, ngoại trừ một lớp kiểu Logger. Rất có khả năng người dùng của bạn muốn ghi nhật ký thứ gì đó cho đến giây phút cuối cùng có thể. Vì vậy, cô ấy có thể đăng nhập một ngoại lệ chưa được xử lý từ AppDomain.UnhandledException chẳng hạn.
Khi nào cần gọi Dispose() trong trường hợp này? Bạn có thể làm điều đó khi chương trình của bạn chấm dứt. Nhưng đó là kinda ngoài điểm, không có nhiều điểm trong việc phát hành tài nguyên sớm nếu nó xảy ra khi chương trình đang thoát.
Trình ghi nhật ký có yêu cầu đặc biệt để tắt đúng cách trong mọi trường hợp. Điều đó yêu cầu bạn đặt thuộc tính StreamWriter.AutoFlush thành true để đầu ra ghi nhật ký bị xóa ngay khi được ghi. Với sự khó khăn của việc gọi Dispose() đúng, bây giờ thực sự tốt hơn là bạn không thực hiện IDisposable và để cho trình finalizer của Microsoft đóng trình xử lý tệp.
Fwiw, có một lớp khác trong khuôn khổ có cùng vấn đề. Lớp Thread sử dụng bốn xử lý hệ điều hành nhưng không thực hiện IDisposable. Gọi Thread.Dispose() là thực sự khó xử, vì vậy Microsoft đã không thực hiện nó. Điều này gây ra các sự cố trong rất trường hợp bất thường, bạn cần viết chương trình tạo nhiều luồng nhưng không bao giờ sử dụng toán tử mới để tạo đối tượng lớp. Nó đã được thực hiện.
Cuối cùng nhưng không kém phần quan trọng: viết nhật ký khá phức tạp như đã giải thích ở trên. Log4net là một giải pháp phổ biến. NLog là một cái bẫy chuột tốt hơn, một thư viện mà cảm thấy và hoạt động dotnetty thay vì cảm thấy giống như một cổng Java.
Có một mẫu chính xác để triển khai các đối tượng dùng một lần với các trình phá hủy. Đây không phải là nó. Như bạn đã khám phá, nếu bạn nhận được mẫu sai, bạn sẽ có được niềm vui của việc gỡ lỗi các lỗi trên trình hoàn thiện. Đọc lên trên mẫu và thực hiện nó một cách chính xác. http://msdn.microsoft.com/en-us/magazine/cc163392.aspx –