Hoàn thiện vs Vứt bỏ


Câu trả lời:


120

Những người khác đã đề cập đến sự khác biệt giữa DisposeFinalize(btw Finalizephương thức vẫn được gọi là hàm hủy trong đặc tả ngôn ngữ), vì vậy tôi sẽ chỉ thêm một chút về các tình huống mà Finalizephương thức này có ích.

Một số loại đóng gói các tài nguyên dùng một lần theo cách dễ sử dụng và loại bỏ chúng trong một hành động. Cách sử dụng chung thường như thế này: mở, đọc hoặc viết, đóng (Vứt bỏ). Nó rất phù hợp với usingcấu trúc.

Những người khác là một chút khó khăn hơn. WaitEventHandlesđối với các trường hợp không được sử dụng như thế này vì chúng được sử dụng để báo hiệu từ luồng này sang luồng khác. Câu hỏi sau đó trở thành ai nên kêu gọi Disposenhững điều này? Vì các kiểu bảo vệ như thế này thực hiện một Finalizephương thức, điều này đảm bảo các tài nguyên được xử lý khi cá thể không còn được ứng dụng tham chiếu nữa.


60
Tôi không thể hiểu câu trả lời được phê duyệt này. Tôi vẫn muốn biết sự khác biệt. Nó là gì
Ismael

22
@Ismael: Tình huống lớn nhất Finalizecó thể được biện minh là khi có một số đối tượng quan tâm đến việc giữ tài nguyên tồn tại, nhưng không có cách nào mà một đối tượng ngừng quan tâm đến tài nguyên có thể tìm ra nếu đó là cái cuối cùng. Trong trường hợp như vậy, Finalizethường sẽ chỉ bắn khi không ai quan tâm đến đối tượng. Thời gian lỏng lẻo Finalizelà khủng khiếp đối với các tài nguyên không bị nấm như tệp và khóa, nhưng có thể ổn đối với tài nguyên có thể bị nấm.
supercat

13
+1 để supercat cho một từ mới (với tôi) tuyệt vời. Bối cảnh đã cho thấy khá rõ ràng, nhưng chỉ trong trường hợp với phần còn lại của chúng tôi, đây là những gì wikipedia nói: "Tính linh hoạt là tài sản của hàng hóa hoặc hàng hóa mà các đơn vị riêng lẻ có khả năng thay thế lẫn nhau, như dầu thô ngọt, cổ phần trong một công ty, trái phiếu, kim loại quý hoặc tiền tệ. "
Jon Coombs

5
@JonCoombs: Điều đó khá đúng, mặc dù có thể đáng chú ý rằng thuật ngữ "tài nguyên nấm" được áp dụng cho những thứ có thể thay thế tự do cho đến khi chúng được mua lại và trở thành tự do thay thế một lần nữa sau khi phát hành hoặc từ bỏ . Nếu hệ thống có một nhóm các đối tượng khóa và mã có được một đối tượng mà nó liên kết với một thực thể nào đó, thì miễn là bất cứ ai đang giữ tham chiếu đến khóa đó với mục đích liên kết nó với thực thể đó, khóa đó có thể không được thay thế bằng bất kỳ khác. Tuy nhiên, nếu tất cả các mã quan tâm đến thực thể được bảo vệ đều bỏ khóa, ...
supercat

... sau đó nó sẽ lại trở thành tự do thay thế cho đến khi nó được liên kết với một số thực thể khác.
supercat

135

Phương thức hoàn thiện được gọi khi đối tượng của bạn là rác được thu thập và bạn không có gì đảm bảo khi điều này xảy ra (bạn có thể buộc nó, nhưng nó sẽ làm giảm hiệu suất).

Mặt khác, Disposephương thức này được gọi là mã đã tạo lớp của bạn để bạn có thể dọn sạch và giải phóng bất kỳ tài nguyên nào bạn có được (dữ liệu không được quản lý, kết nối cơ sở dữ liệu, xử lý tệp, v.v.) ngay khi mã được thực hiện đối tượng của bạn.

Thực hành tiêu chuẩn là thực hiện IDisposableDisposeđể bạn có thể sử dụng đối tượng của mình trong một thống kê using. Chẳng hạn như using(var foo = new MyObject()) { }. Và trong trình hoàn thiện của bạn, bạn gọi Dispose, chỉ trong trường hợp mã cuộc gọi quên không xử lý bạn.


17
Bạn cần cẩn thận một chút về việc gọi Vứt bỏ khỏi triển khai Hoàn tất của mình - Vứt bỏ cũng có thể loại bỏ các tài nguyên được quản lý mà bạn không muốn chạm vào từ bộ hoàn thiện của mình, vì chúng có thể đã được hoàn thiện.
itowlson

6
@itowlson: Kiểm tra null kết hợp với giả định rằng các đối tượng có thể được xử lý hai lần (với cuộc gọi thứ hai không làm gì) là đủ tốt.
Samuel

7
Mẫu IDisposed tiêu chuẩn và triển khai ẩn của Dispose (bool) để xử lý các thành phần được quản lý tùy chọn dường như để phục vụ cho vấn đề đó.
Brody

Có vẻ như không có lý do gì để thực hiện hàm hủy (phương thức ~ MyClass ()) và thay vào đó luôn luôn thực hiện và gọi phương thức Dispose (). Hoặc là tôi sai? Ai đó có thể cho tôi một ví dụ khi cả hai nên được thực hiện?
dpelisek

66

Hoàn thiện là phương thức backstop, được gọi bởi trình thu gom rác khi nó lấy lại một đối tượng. Vứt bỏ là phương pháp "dọn dẹp xác định", được các ứng dụng gọi để giải phóng các tài nguyên bản địa có giá trị (tay cầm cửa sổ, kết nối cơ sở dữ liệu, v.v.) khi chúng không còn cần thiết, thay vì để chúng giữ vô thời hạn cho đến khi GC đi vòng quanh đối tượng.

Là người dùng của một đối tượng, bạn luôn sử dụng Vứt bỏ. Hoàn thiện là dành cho GC.

Là người triển khai của một lớp, nếu bạn giữ các tài nguyên được quản lý phải được xử lý, bạn sẽ thực hiện Vứt bỏ. Nếu bạn giữ tài nguyên riêng, bạn triển khai cả Vứt bỏ và Hoàn thiện và cả hai đều gọi một phương thức chung giải phóng tài nguyên bản địa. Các thành ngữ này thường được kết hợp thông qua một phương thức Dispose (bool dispose) riêng, loại bỏ các cuộc gọi với true và Hoàn tất các cuộc gọi với false. Phương pháp này luôn giải phóng các tài nguyên bản địa, sau đó kiểm tra tham số xử lý và nếu đúng, nó xử lý các tài nguyên được quản lý và gọi GC.SuppressFinalize.



2
Mẫu đề xuất ban đầu cho các lớp tổ chức hỗn hợp các tài nguyên tự làm sạch ("được quản lý") và không tự làm sạch ("không được quản lý") từ lâu đã trở nên lỗi thời. Một mô hình tốt hơn là bọc riêng mọi tài nguyên không được quản lý vào đối tượng được quản lý riêng của nó mà không chứa bất kỳ tham chiếu mạnh nào đến bất kỳ thứ gì không cần thiết cho việc dọn dẹp. Tất cả mọi thứ mà một đối tượng có thể hoàn thiện giữ một tham chiếu mạnh trực tiếp hoặc gián tiếp sẽ được kéo dài vòng đời của nó. Đóng gói những thứ cần thiết để dọn dẹp sẽ cho phép người ta tránh kéo dài tuổi thọ của những thứ không tồn tại.
supercat

2
@JCoombs: Disposelà tốt, và thực hiện nó một cách chính xác nói chung là dễ dàng. Finalizelà xấu xa, và thực hiện nó một cách chính xác nói chung là khó khăn. Trong số những thứ khác, bởi vì GC sẽ đảm bảo rằng không có danh tính của đối tượng sẽ được "tái chế" miễn là có bất kỳ tham chiếu nào đến đối tượng đó, nên việc dọn sạch một loạt các Disposableđối tượng, một số trong đó có thể đã được làm sạch, là không vấn đề gì; mọi tham chiếu đến một đối tượng Disposeđã được gọi sẽ vẫn là một tham chiếu đến một đối tượng mà nó Disposeđã được gọi.
supercat

2
@JCoombs: Ngược lại, tài nguyên không được quản lý, thường không có sự đảm bảo như vậy. Nếu đối tượng Fredsở hữu tệp xử lý số 42 và đóng nó, hệ thống có thể đính kèm số đó vào một số xử lý tệp được trao cho một số thực thể khác. Trong trường hợp đó, tệp xử lý số 42 sẽ không đề cập đến tệp đã đóng của Fred, mà là tệp được sử dụng bởi thực thể khác đó; cho Fredđể cố gắng gần gũi xử lý # 42 một lần nữa sẽ là thảm hoạ. Cố gắng 100% đáng tin cậy để theo dõi xem một đối tượng không được quản lý đã được phát hành có khả thi hay không. Cố gắng theo dõi nhiều đối tượng khó hơn nhiều.
supercat

2
@JCoombs: Nếu mọi tài nguyên không được quản lý được đặt trong đối tượng trình bao bọc riêng của nó mà không kiểm soát được vòng đời của nó, thì mã bên ngoài không biết liệu tài nguyên đã được phát hành hay chưa, nhưng biết rằng nó sẽ là nếu nó chưa được , có thể yêu cầu đối tượng trình bao bọc giải phóng nó một cách an toàn; đối tượng trình bao bọc sẽ biết nếu nó đã làm như vậy và có thể thực hiện hoặc bỏ qua yêu cầu. Việc GC đảm bảo rằng một tham chiếu đến trình bao bọc sẽ luôn là một tham chiếu hợp lệ cho trình bao bọc là một đảm bảo rất hữu ích .
supercat

43

Hoàn thiện

  • Các trình hoàn thiện phải luôn luôn protected, không publichoặc privateđể phương thức không thể được gọi trực tiếp từ mã của ứng dụng và đồng thời, nó có thể thực hiện cuộc gọi đến base.Finalizephương thức
  • Người hoàn thiện chỉ nên giải phóng tài nguyên không được quản lý.
  • Khung không đảm bảo rằng bộ hoàn thiện sẽ thực hiện ở tất cả các trường hợp cụ thể.
  • Không bao giờ phân bổ bộ nhớ trong bộ hoàn thiện hoặc gọi phương thức ảo từ bộ hoàn thiện.
  • Tránh đồng bộ hóa và đưa ra các ngoại lệ chưa được xử lý trong các quyết toán.
  • Thứ tự thực hiện của bộ hoàn thiện là không xác định, nói cách khác, bạn không thể dựa vào một đối tượng khác vẫn có sẵn trong bộ hoàn thiện của bạn.
  • Không xác định cuối cùng về các loại giá trị.
  • Đừng tạo ra các hàm hủy rỗng. Nói cách khác, bạn không bao giờ nên xác định rõ ràng một hàm hủy trừ khi lớp của bạn cần dọn sạch các tài nguyên không được quản lý và nếu bạn xác định một tài nguyên, nó sẽ thực hiện một số công việc. Nếu, sau này, bạn không còn cần phải dọn sạch các tài nguyên không được quản lý trong hàm hủy, hãy loại bỏ nó hoàn toàn.

Vứt bỏ

  • Thực hiện IDisposabletrên mọi loại có bộ hoàn thiện
  • Đảm bảo rằng một đối tượng được thực hiện không sử dụng được sau khi thực hiện cuộc gọi đến Disposephương thức. Nói cách khác, tránh sử dụng một đối tượng sau khi Disposephương thức đã được gọi trên nó.
  • Gọi Disposetất cả các IDisposableloại khi bạn đã hoàn thành với chúng
  • Cho phép Disposeđược gọi nhiều lần mà không tăng lỗi.
  • Bỏ qua các cuộc gọi sau đó đến bộ hoàn thiện từ bên trong Disposephương thức bằng GC.SuppressFinalizephương thức
  • Tránh tạo các loại giá trị dùng một lần
  • Tránh ném ngoại lệ từ bên trong Disposecác phương thức

Vứt bỏ / Hoàn thiện mẫu

  • Microsoft khuyên bạn nên triển khai cả DisposeFinalizekhi làm việc với các tài nguyên không được quản lý. Việc Finalizetriển khai sẽ chạy và các tài nguyên vẫn sẽ được giải phóng khi đối tượng là rác được thu thập ngay cả khi nhà phát triển bỏ qua việc gọi Disposephương thức một cách rõ ràng.
  • Dọn dẹp các tài nguyên không được quản lý trong Finalizephương pháp cũng như Disposephương pháp. Ngoài ra, gọi Disposephương thức cho bất kỳ đối tượng .NET nào mà bạn có như các thành phần bên trong lớp đó (có tài nguyên không được quản lý làm thành viên của chúng) từ Disposephương thức.

17
Tôi đọc cùng một câu trả lời ở khắp mọi nơi và tôi vẫn không thể hiểu mục đích của mỗi người là gì. Tôi chỉ đọc quy tắc sau quy tắc, không có gì hơn.
Ismael

@Ismael: và tác giả cũng không thêm bất cứ thứ gì ngoại trừ việc sao chép và dán một số văn bản từ MSDN.
Tarik

@tarik Mình đã học nó rồi. Tôi đã có "lời hứa" quan niệm rằng lần đó tôi đã hỏi điều này.
Ismael

31

Hoàn thiện được gọi bởi GC khi đối tượng này không còn được sử dụng.

Vứt bỏ chỉ là một phương thức bình thường mà người dùng của lớp này có thể gọi để giải phóng bất kỳ tài nguyên nào.

Nếu người dùng quên gọi Vứt bỏ và nếu lớp đã Hoàn tất triển khai thì GC sẽ đảm bảo nó được gọi.


3
Câu trả lời sạch nhất từ ​​trước đến nay
dariogriffo

19

Có một số chìa khóa trong cuốn sách Bộ công cụ chứng nhận MCSD (kỳ thi 70-483) trang 193:

hàm hủy (gần như bằng)base.Finalize() , hàm hủy được chuyển đổi thành phiên bản ghi đè của phương thức Finalize thực thi mã của hàm hủy và sau đó gọi phương thức Finalize của lớp cơ sở. Sau đó, nó hoàn toàn không mang tính quyết định mà bạn không thể biết khi nào sẽ được gọi vì phụ thuộc vào GC.

Nếu một lớp không chứa tài nguyên được quản lý và không có tài nguyên không được quản lý , thì nó không nên thực hiện IDisposablehoặc có hàm hủy.

Nếu lớp chỉ có các tài nguyên được quản lý , nó sẽ thực hiện IDisposablenhưng nó không nên có hàm hủy. (Khi hàm hủy thực thi, bạn không thể chắc chắn các đối tượng được quản lý vẫn tồn tại, do đó bạn không thể gọi Dispose()phương thức của chúng bằng mọi cách.)

Nếu lớp chỉ có các tài nguyên không được quản lý , nó cần thực hiện IDisposablevà cần một hàm hủy trong trường hợp chương trình không gọi Dispose().

Dispose()phương pháp phải an toàn để chạy nhiều lần. Bạn có thể đạt được điều đó bằng cách sử dụng một biến để theo dõi xem nó đã được chạy trước đó chưa.

Dispose()nên giải phóng cả tài nguyên được quản lý và không được quản lý .

Các hàm hủy chỉ nên giải phóng các tài nguyên không được quản lý . Khi hàm hủy thực thi, bạn không thể chắc chắn các đối tượng được quản lý vẫn tồn tại, do đó bạn không thể gọi các phương thức Vứt bỏ của chúng bằng mọi cách. Điều này có được bằng cách sử dụng protected void Dispose(bool disposing)mẫu chính tắc , trong đó chỉ các tài nguyên được quản lý được giải phóng (xử lý) khi disposing == true.

Sau khi giải phóng tài nguyên, Dispose()nên gọiGC.SuppressFinalize , để đối tượng có thể bỏ qua hàng đợi quyết toán.

Một ví dụ về việc triển khai cho một lớp với các tài nguyên không được quản lý và quản lý:

using System;

class DisposableClass : IDisposable
{
    // A name to keep track of the object.
    public string Name = "";

    // Free managed and unmanaged resources.
    public void Dispose()
    {
        FreeResources(true);

        // We don't need the destructor because
        // our resources are already freed.
        GC.SuppressFinalize(this);
    }

    // Destructor to clean up unmanaged resources
    // but not managed resources.
    ~DisposableClass()
    {
        FreeResources(false);
    }

    // Keep track if whether resources are already freed.
    private bool ResourcesAreFreed = false;

    // Free resources.
    private void FreeResources(bool freeManagedResources)
    {
        Console.WriteLine(Name + ": FreeResources");
        if (!ResourcesAreFreed)
        {
            // Dispose of managed resources if appropriate.
            if (freeManagedResources)
            {
                // Dispose of managed resources here.
                Console.WriteLine(Name + ": Dispose of managed resources");
            }

            // Dispose of unmanaged resources here.
            Console.WriteLine(Name + ": Dispose of unmanaged resources");

            // Remember that we have disposed of resources.
            ResourcesAreFreed = true;
        }
    }
}

2
Đây là một câu trả lời tốt đẹp! Nhưng tôi nghĩ điều này là sai: "kẻ hủy diệt nên gọi GC.SuppressFinalize". Thay vào đó, không nên sử dụng phương thức Dispose () công khai gọi GC.SuppressFinalize? Xem: docs.microsoft.com/en-us/dotnet/api/NH Gọi phương thức này ngăn người thu gom rác gọi Object.Finalize (bị ghi đè bởi hàm hủy).
Ewa

7

99% thời gian, bạn cũng không cần phải lo lắng. :) Nhưng, nếu các đối tượng của bạn giữ các tham chiếu đến các tài nguyên không được quản lý (ví dụ xử lý cửa sổ, xử lý tệp), bạn cần cung cấp một cách để đối tượng được quản lý của bạn giải phóng các tài nguyên đó. Hoàn thiện cho phép kiểm soát ngầm phát hành tài nguyên. Nó được gọi bởi người thu gom rác. Vứt bỏ là một cách để cung cấp quyền kiểm soát rõ ràng đối với việc phát hành tài nguyên và có thể được gọi trực tiếp.

Có nhiều hơn nữa để tìm hiểu về chủ đề của Bộ sưu tập rác , nhưng đó là một sự khởi đầu.


5
Tôi khá chắc chắn rằng hơn 1% ứng dụng C # sử dụng cơ sở dữ liệu: nơi bạn phải lo lắng về các công cụ SQL có thể sử dụng được .
Samuel

1
Ngoài ra, bạn nên triển khai IDis Dùng nếu bạn đóng gói IDisposeables. Mà có lẽ bao gồm 1% khác.
Darren Clark

@Samuel: Tôi không thấy cơ sở dữ liệu phải làm gì với nó. Nếu bạn đang nói về việc đóng kết nối, điều đó tốt, nhưng đó là một vấn đề khác. Bạn không cần phải xử lý các đối tượng để đóng các kết nối kịp thời.
JP Alioto

1
@JP: Nhưng mẫu Sử dụng (...) làm cho nó trở nên đơn giản hơn rất nhiều để đối phó.
Brody

2
Đồng ý, nhưng đó chính xác là vấn đề. Mẫu sử dụng ẩn cuộc gọi đến Vứt bỏ cho bạn.
JP Alioto

6

Công cụ hoàn thiện là để dọn dẹp ngầm - bạn nên sử dụng nó bất cứ khi nào một lớp quản lý các tài nguyên hoàn toàn phải được dọn sạch vì nếu không bạn sẽ rò rỉ tay cầm / bộ nhớ, v.v ...

Việc triển khai chính xác một bộ hoàn thiện là rất khó khăn và nên tránh ở bất cứ nơi nào có thể - SafeHandlelớp (có sẵn trong .Net v2.0 trở lên) có nghĩa là bạn rất hiếm khi (nếu có) cần phải thực hiện một bộ hoàn thiện nữa.

Các IDisposablegiao diện là để dọn dẹp rõ ràng và được sử dụng nhiều hơn nữa thường - bạn nên sử dụng này cho phép người dùng để phát hành một cách rõ ràng hoặc nguồn lực dọn dẹp bất cứ khi nào họ đã hoàn thành sử dụng một đối tượng.

Lưu ý rằng nếu bạn có bộ hoàn thiện thì bạn cũng nên triển khai IDisposablegiao diện để cho phép người dùng giải phóng rõ ràng những tài nguyên đó sớm hơn so với khi đối tượng bị thu gom rác.

Xem Cập nhật DG: Loại bỏ, quyết toán và quản lý tài nguyên để biết những gì tôi cho là tập hợp khuyến nghị tốt nhất và đầy đủ nhất về quyết toán và IDisposable.


3

Tóm tắt là -

  • Bạn viết một trình hoàn thiện cho lớp của mình nếu nó có tham chiếu đến các tài nguyên không được quản lý và bạn muốn đảm bảo rằng các tài nguyên không được quản lý đó được giải phóng khi một phiên bản của lớp đó được thu gom rác tự động . Lưu ý rằng bạn không thể gọi Trình hoàn thiện của một đối tượng một cách rõ ràng - nó được gọi tự động bởi trình thu gom rác khi cần thiết.
  • Mặt khác, bạn triển khai giao diện IDis Dùng (và do đó xác định phương thức Dispose () là kết quả cho lớp của bạn) khi lớp của bạn có tham chiếu đến các tài nguyên không được quản lý, nhưng bạn không muốn đợi trình thu gom rác khởi động (có thể là bất cứ lúc nào - không nằm trong sự kiểm soát của lập trình viên) và muốn giải phóng những tài nguyên đó ngay khi bạn hoàn thành. Do đó, bạn có thể giải phóng rõ ràng các tài nguyên không được quản lý bằng cách gọi phương thức Dispose () của đối tượng.

Ngoài ra, một sự khác biệt khác là - trong triển khai Dispose (), bạn cũng nên giải phóng các tài nguyên được quản lý , trong khi điều đó không nên được thực hiện trong Finalizer. Điều này là do rất có thể các tài nguyên được quản lý được tham chiếu bởi đối tượng đã được dọn sạch trước khi nó sẵn sàng để được hoàn thành.

Đối với một lớp sử dụng các tài nguyên không được quản lý, cách tốt nhất là định nghĩa cả hai - phương thức Dispose () và Finalizer - để được sử dụng như một dự phòng trong trường hợp nhà phát triển quên loại bỏ rõ ràng đối tượng. Cả hai đều có thể sử dụng phương pháp chia sẻ để dọn sạch các tài nguyên được quản lý và không được quản lý: -

class ClassWithDisposeAndFinalize : IDisposable
{
    // Used to determine if Dispose() has already been called, so that the finalizer
    // knows if it needs to clean up unmanaged resources.
     private bool disposed = false;

     public void Dispose()
     {
       // Call our shared helper method.
       // Specifying "true" signifies that the object user triggered the cleanup.
          CleanUp(true);

       // Now suppress finalization to make sure that the Finalize method 
       // doesn't attempt to clean up unmanaged resources.
          GC.SuppressFinalize(this);
     }
     private void CleanUp(bool disposing)
     {
        // Be sure we have not already been disposed!
        if (!this.disposed)
        {
             // If disposing equals true i.e. if disposed explicitly, dispose all 
             // managed resources.
            if (disposing)
            {
             // Dispose managed resources.
            }
             // Clean up unmanaged resources here.
        }
        disposed = true;
      }

      // the below is called the destructor or Finalizer
     ~ClassWithDisposeAndFinalize()
     {
        // Call our shared helper method.
        // Specifying "false" signifies that the GC triggered the cleanup.
        CleanUp(false);
     }

2

Ví dụ tốt nhất mà tôi biết.

 public abstract class DisposableType: IDisposable
  {
    bool disposed = false;

    ~DisposableType()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(false);
      }
    }

    public void Dispose()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(true);
        GC.SuppressFinalize(this);
      }
    }

    public void Close()
    {
      Dispose();
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposing) 
      {
        // managed objects
      }
      // unmanaged objects and resources
    }
  }

2

Khác nhau giữa các phương thức Hoàn thiện và Loại bỏ trong C #.

GC gọi phương thức hoàn thiện để lấy lại các tài nguyên không được quản lý (như thao tác tệp, windows api, kết nối mạng, kết nối cơ sở dữ liệu) nhưng thời gian không được cố định khi GC sẽ gọi nó. Nó được gọi là ngầm bởi nó có nghĩa là chúng tôi không có quyền kiểm soát cấp thấp đối với nó.

Phương pháp loại bỏ: Chúng tôi có quyền kiểm soát mức độ thấp đối với nó khi chúng tôi gọi nó từ mã. chúng tôi có thể lấy lại các tài nguyên không được quản lý bất cứ khi nào chúng tôi cảm thấy không thể sử dụng được. Chúng tôi có thể đạt được điều này bằng cách triển khai mẫu IDisposed.


1

Các thể hiện của lớp thường đóng gói kiểm soát các tài nguyên không được quản lý bởi thời gian chạy, chẳng hạn như các điều khiển cửa sổ (HWND), các kết nối cơ sở dữ liệu, v.v. Do đó, bạn nên cung cấp cả một cách rõ ràng và một cách ngầm để giải phóng những tài nguyên đó. Cung cấp điều khiển ngầm bằng cách triển khai Phương thức Hoàn thiện được bảo vệ trên một đối tượng (cú pháp hàm hủy trong C # và Phần mở rộng được quản lý cho C ++). Trình thu gom rác gọi phương thức này tại một số điểm sau khi không còn bất kỳ tham chiếu hợp lệ nào cho đối tượng. Trong một số trường hợp, bạn có thể muốn cung cấp cho các lập trình viên sử dụng một đối tượng với khả năng giải phóng rõ ràng các tài nguyên bên ngoài này trước khi trình thu gom rác giải phóng đối tượng. Nếu một nguồn tài nguyên bên ngoài khan hiếm hoặc đắt tiền, hiệu suất tốt hơn có thể đạt được nếu lập trình viên giải phóng rõ ràng tài nguyên khi chúng không còn được sử dụng. Để cung cấp kiểm soát rõ ràng, hãy triển khai phương thức Vứt bỏ do Giao diện IDis cung cấp. Người tiêu dùng của đối tượng nên gọi phương thức này khi nó được thực hiện bằng cách sử dụng đối tượng. Vứt bỏ có thể được gọi ngay cả khi các tham chiếu khác đến đối tượng còn sống.

Lưu ý rằng ngay cả khi bạn cung cấp kiểm soát rõ ràng bằng cách Loại bỏ, bạn nên cung cấp dọn dẹp ngầm bằng phương pháp Hoàn thiện. Finalize cung cấp một bản sao lưu để ngăn chặn tài nguyên bị rò rỉ vĩnh viễn nếu lập trình viên không gọi được Dispose.


1

Sự khác biệt chính giữa Vứt bỏ và Hoàn thiện là:

Disposethường được gọi bởi mã của bạn. Các tài nguyên được giải phóng ngay lập tức khi bạn gọi nó. Mọi người quên gọi phương thức, vì vậy using() {}câu lệnh được phát minh. Khi chương trình của bạn kết thúc việc thực thi mã bên trong {}, nó sẽ Disposetự động gọi phương thức.

Finalizekhông được gọi bởi mã của bạn. Nó có nghĩa là được gọi bởi Garbage Collector (GC). Điều đó có nghĩa là tài nguyên có thể được giải phóng bất cứ lúc nào trong tương lai bất cứ khi nào GC quyết định làm như vậy. Khi GC thực hiện công việc của mình, nó sẽ trải qua nhiều phương thức Hoàn thiện. Nếu bạn có logic nặng trong việc này, nó sẽ làm cho quá trình chậm lại. Nó có thể gây ra vấn đề hiệu suất cho chương trình của bạn. Vì vậy, hãy cẩn thận về những gì bạn đặt trong đó.

Cá nhân tôi sẽ viết phần lớn logic phá hủy trong Vứt bỏ. Hy vọng, điều này sẽ làm sáng tỏ sự nhầm lẫn.


-1

Như chúng ta đã biết, xử lý và hoàn thiện cả hai đều được sử dụng để giải phóng tài nguyên không được quản lý .. nhưng sự khác biệt là hoàn thiện sử dụng hai chu kỳ để giải phóng tài nguyên, trong khi xử lý sử dụng một chu kỳ ..


Vứt bỏ tài nguyên ngay lập tức. Hoàn thiện có thể hoặc không thể giải phóng tài nguyên với bất kỳ mức độ kịp thời nào.
supercat

1
À, anh ta có thể có nghĩa là "một vật thể hoàn thiện cần được phát hiện bởi GC hai lần trước khi lấy lại bộ nhớ của nó", đọc thêm tại đây: ericlippert.com/2015/05/18/
aeroson

-4

Để trả lời về phần đầu tiên, bạn nên cung cấp các ví dụ nơi mọi người sử dụng cách tiếp cận khác nhau cho cùng một đối tượng lớp chính xác. Nếu không thì rất khó (hoặc thậm chí là lạ) để trả lời.

Đối với câu hỏi thứ hai, trước tiên hãy đọc tốt hơn Giao diện IDis Dùng để xác nhận rằng

Đó là sự lựa chọn của bạn! Nhưng chọn Vứt bỏ.

Nói cách khác: GC chỉ biết về bộ hoàn thiện (nếu có. Còn được gọi là hàm hủy đối với Microsoft). Một mã tốt sẽ cố gắng dọn sạch từ cả hai (bộ hoàn thiện và Loại bỏ).

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.