2011-08-03 37 views
11

Tôi có một Winform trống với một phương pháp destructorTại sao destructor của tôi không bao giờ chạy?

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     System.Diagnostics.Trace.WriteLine("Form1.Initialize " + this.GetHashCode().ToString()); 
     InitializeComponent(); 
    } 
    ~Form1() 
    { 
     System.Diagnostics.Trace.WriteLine("Form1.Dispose " + this.GetHashCode().ToString()); 
    } 
} 

Khi các hình thức bị hủy diệt, tôi muốn nó ghi vào sổ đầu ra:

 
(Form1 opened) 
Form1.Initialize 41149443 
(Form1 closed) 
Form1.Dispose 41149443 

MSDN gợi ý 3 cách thực hiện destructor:

Tuy nhiên, không ai trong số những cách viết "Form1.Dispose 41.149.443" vào cửa sổ đầu ra. Vì vậy, tôi không thể biết liệu biểu mẫu đã bị hủy hay chưa. Gợi ý?

Tôi có nên từ bỏ hy vọng đạt được điều này do sự không chắc chắn của bộ thu gom rác không?

Có cách nào khác để biết liệu Form1 có bị thu gom rác không?

+0

Tại sao? Bạn đang cố làm gì vậy? – SLaks

+0

Bạn không thể giả định rằng destructor sẽ được gọi. (Ví dụ, nếu bạn có đủ bộ nhớ, nó hoàn toàn hợp lệ không bao giờ gọi bất kỳ destructor, bao giờ hết.) – katrielalex

+0

Không phải là dấu vết được viết? –

Trả lời

9

Chỉ một trong ba cách để triển khai trình phá hủy mà bạn liệt kê thực sự liên quan đến một trình phá hủy và đó là ~Destructor().

Nếu bạn triển khai IDisposable và xử lý đối tượng của mình, khi đó mã trong Dispose sẽ chạy, nhưng không có lý do gì để nghĩ rằng trình phá hủy của bạn sẽ.

Tôi nghĩ bạn theo đuổi điều không thể ở đây. Destructors chạy như và khi thu gom rác để nghị định. Nó không phải là một cái gì đó mà bạn có bất kỳ kiểm soát. GC cũng nằm trong quyền của mình để hình thành ý kiến ​​rằng việc chạy các destructors chỉ đơn giản là lãng phí thời gian, và nếu có nhiều bộ nhớ, nó sẽ hình thành ý kiến ​​đó.

Nếu bạn cần xử lý có thể dự đoán, hoàn tất, v.v., sau đó sử dụng IDisposable.

+0

IDisposable không thể tự động dự đoán được, bạn phải gọi Dispose hoặc sử dụng using(). Và làm thế nào bạn sẽ gọi Dispose()? – slfan

+1

@slfan Bạn đang nói về cái gì? 'Dispose' chạy khi nó được gọi, luôn luôn thông qua' using'. Tôi đã nói rằng 'Vứt bỏ' sẽ chạy tự động ở đâu? –

+0

Bạn đã viết "nếu bạn cần xử lý có thể dự đoán được ...". Nếu bạn không sử dụng hoặc gọi nó một cách rõ ràng, nó không được gọi. Như tôi chưa bao giờ sử dụng với một biểu mẫu, nó thậm chí còn ít có thể dự đoán được hơn finalizer. – slfan

1

Có, bạn có lẽ nên từ bỏ ý tưởng về hàm hủy, bởi vì chúng không mang tính xác định. Tôi không chắc chắn lý do tại sao bạn cần phải có biểu mẫu được xử lý như trái ngược với chỉ đóng, nhưng chỉ cần đóng nó là đủ trong hầu hết các trường hợp.

Bạn có thể sử dụng IDisposable nhưng điều đó phụ thuộc vào lý do bạn cần biểu mẫu thu thập rác. Nếu bạn cần tái sử dụng nó, chỉ cần tạo một thể hiện khác.

1

Biểu mẫu thu thập rác khi không có tham chiếu nào tồn tại và trình thu gom rác sẽ xảy ra để chạy. Bạn có thể ép bộ thu gom rác bằng cách gọi GC.Collect(). Bạn không nên tham chiếu bất kỳ đối tượng nào khác trong Finalizer (còn gọi là destructor) vì đối tượng có thể đã bị thu gom rác.

Bạn có thể sử dụng các công cụ phân tích bộ nhớ để tìm hiểu xem đối tượng của bạn có bị thu gom rác hay không, nếu bạn thực sự cần.

Bạn cũng phải lưu ý rằng trình kết thúc được gọi từ một chuỗi khác với chuỗi chính.

EDIT: Nếu vấn đề của bạn là chỉ mà bạn không nhìn thấy dấu vết đầu ra, bạn có thể phải quay autoflush trên

<configuration> 
    <system.diagnostics> 
    <trace autoflush="true" /> 
    </system.diagnostics> 
</configuration> 

EDIT 2: Có thể có một tài liệu tham khảo bên ngoài để hình của bạn, chẳng hạn như trình xử lý sự kiện đã đăng ký. Tôi khuyên bạn nên thêm nút trong khu vực quản trị của ứng dụng của bạn để thực thi mã sau:

GC.Collect(); 
GC.WaitForPendingFinalizers(); 
GC.Collect(); 

Giống như trình thu gom rác này phải chạy và phá hủy biểu mẫu của bạn (đặt điểm ngắt vào finalizer). Nếu không, bạn có một số tham chiếu đến đối tượng đã bị hủy.

+0

Vâng, tính năng tự động quét vẫn không giải quyết được vấn đề. –

+0

Ok, hãy thử đoán lần 2 của tôi. Có thể bạn có một số tham chiếu đến biểu mẫu. – slfan

+0

Tôi đã thử tùy chọn thứ 2 và nó hoạt động. Tôi nghĩ bạn là câu trả lời gần nhất so với những người khác. –

4

Trừ khi bạn đang nghiên cứu bộ sưu tập rác, hủy diệt không phải là nơi để bạn truy tìm. Bạn nên xem xét Dispose (có thể overridable trong Form). Điều này xảy ra sau khi tài nguyên không được quản lý (như xử lý cửa sổ của bạn) đã được phát hành.

protected override void Dispose(bool disposing) 
{ 
    System.Diagnostics.Trace.WriteLine(
     "Form1.Dispose " + (disposing ? "disposing " : "") 
     + this.GetHashCode().ToString()); 
    base.Dispose (disposing); 
} 

Nếu bạn muốn xem biểu mẫu/kiểm soát đã được xử lý, hãy sử dụng thuộc tính Control.IsDisposed.

Chỉnh sửa: Do GC.SuppressFinalize, phương thức hoàn thiện của bạn (cú pháp hủy trong C#) sẽ không bao giờ thực thi nếu Vứt bỏ được gọi một cách rõ ràng (hoặc theo khuôn khổ).

Để biết thêm thông tin, hãy xem Implementing a Dispose Method.

+0

@ agent-j không phải là "Form1.Dispose" + (xử lý? "Disposing": "") ' – apacay

+0

@apacay, cảm ơn. cố định –

+0

@slfan, quan điểm của tôi là điều này được gọi bởi finalizer chỉ khi cần thiết. Nếu ai đó hủy bỏ biểu mẫu một cách rõ ràng, hàm hủy (phương thức finilize) có khả năng không bao giờ được thực thi vì GC.SupressFinalize. Xem mẫu Vứt bỏ để biết thêm thông tin. –

0

Bạn có thể thử gói biểu mẫu của mình trong đối tượng WeakReference, sau đó kiểm tra thuộc tính IsAlive của nó để xác định xem nó đã được thu gom rác chưa. Nhưng, vâng ... theo các câu trả lời khác bạn có thể tốt hơn để rời khỏi nó và tin tưởng GC để thực hiện công việc của mình!

1

Thêm sự kiện FormClosed vào trình thiết kế.

ví dụ:

this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(Form1_FormClosed); 

Sau đó, tạo ra các chức năng thích hợp để xử lý sự kiện này.

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