2013-06-06 29 views
5

Tôi đã một lớp C++/CLI có tên là "CTransferManaged" với finalizer thực hiện và destructor:C#/CLI: Destructor không được gọi nếu Dispose() được sử dụng trong nó

CTransferManaged::~CTransferManaged() 
{ 
    this->!CTransferManaged(); 
} 
CTransferManaged::!CTransferManaged() 
{ 
    //Clean up resources... 
} 

Lớp này được bao bọc bởi một lớp C# tên "CTransfer" chứa một đối tượng m_transfer thuộc loại CTransferManaged.

Nếu destructor của lớp này chỉ xóa tham chiếu đến đối tượng m_transfer Tôi có thể thấy rằng các destructor được gọi là (breakpoint là hit):

~CTransfer() 
{ 
    m_transfer = null; //breakpoint on this line 
} 

Nếu tôi gọi Dispose() chức năng của m_transfer đối tượng mà không thay đổi bất cứ điều gì khác, destructor không được gọi nữa (breakpoint không có hit nhiều hơn). Bất kỳ đoán tại sao?

~CTransfer() 
{ 
    m_transfer.Dispose(); //breakpoint on this line 
    m_transfer = null; 
} 

Tôi muốn gọi Dispose() bằng tay kể từ khi tôi phát hiện ra rằng các nguồn lực của đối tượng C++/CLI (m_transfer) đều không được làm sạch đúng cách nếu tôi không gọi Vứt bỏ bằng tay. Tại thời điểm này tôi không biết chính xác lý do tại sao.

Tại sao trình hủy của CTransfer (C# class) không được gọi ngay khi nó gọi CTransferManaged :: Dispose() (C++/CLI)?

+0

Lớp CTransfer của bạn * phải * triển khai IDisposable để có thể xử lý đúng thành viên m_transfer. Có vẻ như bạn đã làm điều đó. Do ** not ** thực hiện một finalizer cho CTransfer. Đặt một thành viên thành null không có tác dụng hữu ích và gọi phương thức Dispose() của nó là sai. –

+0

@HansPassant: Tại sao nó sai khi gọi phương thức Dispose() của đối tượng thành viên (m_transfer) trong trình hoàn thiện của CTransfer? Như tôi đã đề cập, tôi phát hiện ra rằng tài nguyên của m_transfer không được dọn dẹp đúng cách khi tôi không gọi Dispose() trên nó ( obruend

Trả lời

0

C# destructor chỉ được gọi bởi bộ thu gom rác và bạn không thể gọi trực tiếp.

Vứt bỏ là một phần của giao diện IDisposalbe chỉ nên được gọi thủ công và nó sẽ không kích hoạt trình phá hủy.

Thay vì dựa vào destructor, hãy thử triển khai iDisposabe và gọi phương thức Vứt bỏ trực tiếp và đặt mã của bạn ở đó.

Nếu lớp Resource chứa các đối tượng nhúng cần được xử lý, mô hình này là cần thiết với C#:

// C# 
public class Resource : IDisposable 
{ 
    private EmbeddedResource embedded; 

    public Resource() 
    { 
     Console.WriteLine("allocating resource"); 
     embedded = new EmbeddedResource(); 
    } 

    ~Resource() 
    { 
     Dispose(false); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     Console.WriteLine("release resource"); 
     if (disposing) 
     { 
     embedded.Dispose(); 
     } 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
    } 
} 
+0

Lưu ý rằng tôi không muốn bỏ thủ công() đối tượng C# (lớp CTransfer). Tôi chỉ muốn sử dụng xử lý thủ công của thành viên m_transfer (lớp CTransferManaged) vì tài nguyên của nó không được dọn dẹp đúng cách khác. – obruend

0

Các mô hình điển hình cho Vứt bỏ và Hoàn thiện là như vậy mà khi bạn gọi hàm Dispose, finalizer nên bị đè nén . Vứt bỏ là nhằm xóa tài nguyên ngay khi nó được thực hiện, trong khi finalizer có nghĩa là để xóa tài nguyên bất cứ khi nào thu gom rác thu thập các lớp ... Cả hai đều nhằm làm điều tương tự (phát hành tài nguyên không được quản lý), và vì vậy nếu bạn gọi Vứt bỏ, gọi finalizer sau đó sẽ được thừa và không cần thiết, và cũng sẽ gây ra các đối tượng để sống lâu hơn cần thiết vì nó đầu tiên sẽ được đặt trên hàng đợi Finalizer trước khi được thu thập và destructed. Điều này gây ra quản lý bộ nhớ kém trên các ứng dụng được truy cập cao tạo ra và xử lý nhiều đối tượng. Do đó, hầu hết các phương pháp Vứt bỏ trong C# sẽ gọi:

GC.SuppressFinalize(this); 

Điều này yêu cầu bộ thu gom rác không làm trình hoàn thiện. Mẫu này được sử dụng rộng rãi và có thể được sử dụng trong lớp không được quản lý của bạn. Đây có lẽ là lý do tại sao cuộc gọi Dispose loại bỏ destructor.

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