Trong C # sự khác biệt giữa hàm hủy và phương thức Finalize trong một lớp là gì?


96

Sự khác biệt, nếu có, giữa một hàm hủy và một phương thức Finalize trong một lớp là gì?

Gần đây tôi đã phát hiện ra rằng Visual Studio 2008 coi một hàm hủy đồng nghĩa với một phương thức Finalize, có nghĩa là Visual Studio sẽ không cho phép bạn xác định đồng thời cả hai phương thức trong một lớp.

Ví dụ: đoạn mã sau:

class TestFinalize
{
    ~TestFinalize()
    {
        Finalize();
    }

    public bool Finalize()
    {
        return true;
    }
}

Đưa ra lỗi sau khi gọi đến Kết thúc trong trình hủy:

Lời gọi không rõ ràng giữa các phương thức hoặc thuộc tính sau: 'TestFinalize. ~ TestFinalize ()' và 'TestFinalize.Finalize ()'

Và nếu lệnh gọi đến Finalize được nhận xét ra ngoài, nó sẽ xuất hiện lỗi sau:

Nhập 'ManagementCon Khái niệm.Service.TestFinalize' đã xác định một thành viên được gọi là 'Finalize' với các loại tham số giống nhau

Câu trả lời:


68

Một hàm hủy trong C # ghi đè System.Object.Finalizephương thức. Bạn phải sử dụng cú pháp hàm hủy để làm như vậy. Ghi đè thủ công Finalizesẽ cung cấp cho bạn thông báo lỗi.

Về cơ bản những gì bạn đang cố gắng thực hiện với Finalizekhai báo phương thức của mình là ẩn phương thức của lớp cơ sở. Nó sẽ khiến trình biên dịch đưa ra cảnh báo có thể bị tắt tiếng bằng cách sử dụng công cụ newsửa đổi (nếu nó hoạt động). Điều quan trọng cần lưu ý ở đây là bạn không thể cả hai overridevà tuyên bố một newthành viên với tên giống hệt nhau cùng một lúc do đó, có cả một destructor và một Finalizephương pháp sẽ dẫn đến một lỗi (nhưng bạn có thể , mặc dù không được khuyến khích, tuyên bố một public new void Finalize()phương pháp nếu bạn không khai báo hàm hủy).


71

Wikipedia có một số thảo luận tốt về sự khác biệt giữa trình hoàn thiện và trình hủy trong bài viết về trình hoàn thiện .

C # thực sự không có hàm hủy "đúng". Cú pháp giống như một trình hủy C ++, nhưng nó thực sự là một trình hoàn thiện. Bạn đã viết đúng trong phần đầu tiên của ví dụ:

~ClassName() { }

Trên đây là cú pháp đường cho một Finalizehàm. Nó đảm bảo rằng các trình hoàn thiện trong cơ sở được đảm bảo chạy, nhưng nếu không thì giống hệt với việc ghi đè Finalizehàm. Điều này có nghĩa là khi bạn viết cú pháp hàm hủy, bạn thực sự đang viết bộ hoàn thiện.

Theo Microsoft , trình hoàn thiện đề cập đến chức năng mà bộ thu gom rác gọi khi nó thu thập ( Finalize), trong khi trình hủy là bit mã của bạn thực thi kết quả (đường cú pháp trở thành Finalize). Chúng gần giống nhau đến mức Microsoft lẽ ra không bao giờ phân biệt được.

Việc Microsoft sử dụng thuật ngữ "hủy" của C ++ là gây hiểu lầm, bởi vì trong C ++, nó được thực thi trên cùng một luồng ngay sau khi đối tượng bị xóa hoặc bật ra khỏi ngăn xếp, trong khi trong C #, nó được thực thi trên một luồng riêng tại một thời điểm khác.


Tôi cho rằng sự phân biệt như vậy giữa trình hủy và trình hoàn thiện là một điều quan trọng cần thực hiện. Tuy nhiên, chỉ những người quan tâm đến những gì đang diễn ra bên dưới mới quan tâm đến sự khác biệt nói trên.
Kyle Baran

1
Cũng lưu ý rằng ECMA-334 đã chính thức phân định rõ ràng "bộ hủy" và "bộ hoàn thiện" từ lâu. Tôi không biết tại sao MS vẫn nhấn mạnh vào thuật ngữ gây hiểu lầm trong thông số kỹ thuật của họ.
FrankHB

Ít nhất là từ khi làm việc với Mono, C # thực sự được mô hình hóa theo C ++ và hầu hết các đối tượng C # nguyên bản là các đối tượng C ++. Cách thức hoạt động của trình biên dịch đã biên dịch Mono quy định cách các đối tượng C ++ đó bị hủy, và tương tự như vậy, cách thức hoàn thiện đối tượng C # truyền xuống C ++ và gọi các hàm hủy đó. Sự phân biệt có ý nghĩa dưới mui xe, nhưng nó vẫn không thực sự áp dụng cho chính C #.
Kenzi

20

Tìm thấy tại đây: http://sanjaysainitech.blogspot.com/2007/06/difference-between-destructor-dispose.html

  1. Kẻ hủy diệt

    Chúng là các phương thức đặc biệt chứa mã dọn dẹp cho đối tượng. Bạn không thể gọi chúng một cách rõ ràng trong mã của mình vì chúng được gọi ngầm bởi GC. Trong C #, chúng có cùng tên với tên lớp đứng trước ~dấu. Giống-

    Class MyClass
    {
    
    ~MyClass()
    {
    .....
    }
    }
    

    Trong VB.NET, hàm hủy được thực hiện bằng cách ghi đè phương thức Finalize của lớp System.Object.

  2. Vứt bỏ

    Đây cũng giống như bất kỳ phương thức nào khác trong lớp và có thể được gọi một cách rõ ràng nhưng chúng có mục đích đặc biệt là dọn dẹp đối tượng. Trong phương thức định đoạt, chúng ta viết mã dọn dẹp cho đối tượng. Điều quan trọng là chúng ta phải giải phóng tất cả các nguồn không được quản lý trong phương thức vứt bỏ như kết nối cơ sở dữ liệu, tệp, v.v. Lớp thực hiện phương thức vứt bỏ phải triển khai giao diện IDisposable. Phương thức Dispose nên gọi phương thức GC.SuppressFinalize cho đối tượng mà nó đang xử lý nếu lớp có hàm hủy bởi vì nó đã thực hiện công việc dọn dẹp đối tượng, khi đó trình thu gom rác không cần thiết phải gọi phương thức Finalize của đối tượng. Tham khảo: http://msdn2.microsoft.com/en-us/library/aa720161(VS.71).aspx

  3. Hoàn thiện

    Phương thức Finalize hoạt động như một biện pháp bảo vệ để dọn dẹp tài nguyên trong trường hợp phương thức Dispose của bạn không được gọi. Bạn chỉ nên triển khai phương thức Finalize để dọn dẹp các tài nguyên không được quản lý. Bạn không nên triển khai phương thức Finalize cho các đối tượng được quản lý vì trình thu gom rác tự động dọn dẹp các tài nguyên được quản lý. Phương thức Finalize được gọi bởi GC một cách ngầm định, do đó bạn không thể gọi nó từ mã của mình.

    Lưu ý: Trong C #, không thể ghi đè phương thức Finalize, vì vậy bạn phải sử dụng hàm hủy mà phương thức thực thi bên trong sẽ ghi đè phương thức Finalize trong MSIL. Nhưng trong VB.NET, phương thức Finalize có thể bị ghi đè vì nó hỗ trợ phương thức hủy.

Cập nhật: Chủ đề liên quan đến bán thú vị ở đây .


1
You should only implement a Finalize method to clean up unmanaged resources: bạn đưa nó vào Finalize. Tương tự với Vứt bỏ?
hqt

@hqt: Các trường hợp mà người ta nên triển khai Disposenhiều hơn rất nhiều so với những trường hợp người ta nên triển khai trình hoàn thiện. Triển khai Disposenếu có khả năng là một phiên bản của lớp hoặc lớp dẫn xuất sẽ là thứ cuối cùng sở hữu trực tiếp tài nguyên không được quản lý hoặc trực tiếp sở hữu thứ cuối cùng trực tiếp sở hữu tài nguyên không được quản lý hoặc trực tiếp sở hữu thứ cuối cùng trực tiếp sở hữu v.v ... Chỉ triển khai Finalizeđể dọn dẹp tài nguyên nếu lớp của một người <i> trực tiếp </i> sở hữu tài nguyên không được quản lý <i> và hầu như không có gì khác </i> - một tình huống hẹp hơn nhiều.
supercat

@hqt: Nếu một lớp trực tiếp sở hữu các tài nguyên không được quản lý và cũng chứa các tham chiếu đến các đối tượng khác, thì các tài nguyên không được quản lý thường được tách thành lớp có thể hoàn thiện của riêng chúng (lý tưởng là không chứa bất kỳ tham chiếu mạnh nào đến bất kỳ thứ gì khác), nghĩa là lớp mà chứa các tham chiếu đến các đối tượng khác sẽ chỉ sở hữu "những thứ trực tiếp sở hữu tài nguyên không được quản lý", chứ không sở hữu chính tài nguyên đó và do đó sẽ không cần trình hoàn thiện.
supercat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.