2010-03-06 31 views
5

Trình theo dõi joelonsoftware dài hạn, áp phích xếp chồng lần đầu tiên.Truy cập thuộc tính Văn bản của điều khiển sau biểu mẫu gốc Vứt bỏ() 'd?

Tôi muốn biết "làm thế nào một cách an toàn" Tôi có thể làm như sau (C#):

Form formDlg = new Form(); 
TextBox box = new TextBox(); 
formDlg.Controls.Add(box); 
formDlg.ShowDialog(); 
formDlg.Dispose(); 
string sUserEntered = box.Text; // After parent Dispose'd! 

Trong thực tế, điều này (rõ ràng) hoạt động, bởi vì hộp (như là một kiểm soát ) có một riêng văn bản trường (chuỗi) mà nó sử dụng để triển khai thuộc tính Văn bản của nó sau khi xử lý cửa sổ bị hủy.

Tôi sẽ không hài lòng với câu trả lời chung "bạn không thể truy cập một đối tượng sau khi được xử lý" vì (1) Tôi không thể tìm thấy bất kỳ sự cấm chăn nào trong tài liệu MS, (2) Tôi không truy cập tài nguyên không được quản lý và (3) mã này không ném bất kỳ ngoại lệ nào (bao gồm cả ObjectDisposedException).

Tôi muốn thực hiện điều này để tôi có thể tạo và sử dụng phương pháp "ShowAndDispose" kết hợp để giảm nguy cơ quên luôn gọi Dispose() sau ShowDialog().

Để làm phức tạp, thay đổi hành vi trong trình gỡ lỗi. Nếu tôi phá vỡ trước khi Dispose(); sau đó Xem nhanh hộp và đi sâu vào số Kiểm soát lớp cơ sở của nó; sau đó bước qua Dispose(); sau đó box.Text trả về ""! Trong các kịch bản khác box.Text trả về văn bản do người dùng nhập.

+0

Tại sao bạn buộc phải bỏ tiền trên biểu mẫu? Đặc biệt là khi bạn không truy cập tài nguyên không được quản lý. Hãy để khuôn khổ/GC chăm sóc nó. EDIT: Tôi có cảm giác rằng bạn có một tình huống phức tạp hơn nhiều so với mã ở trên. – Zyphrax

+0

Không phải một mình, tại sao truy cập vào một hộp văn bản trên một biểu mẫu được xử lý() ...? Tại sao bạn muốn làm điều đó? Không có ý nghĩa với tôi? Điều đó giống như con trỏ trong C, bạn malloc một con trỏ, làm một số công cụ với nó, sau đó giải phóng nó, sau đó dereference con trỏ sau khi được free'd! – t0mm13b

+0

Zyphrax: Biểu mẫu chứa nhiều tài nguyên không được quản lý, 1 cho mỗi Kiểm soát. –

Trả lời

2

Đó là một chi tiết thực hiện rằng mã này chạy mà không có một vấn đề . Các tài sản Control.Text xảy ra để được lưu trữ bởi các lớp kiểm soát để xử lý các TextBox không gây ra một ngoại lệ ObjectDisposed.

Đó là khá hiếm hoi btw, rất nhiều kiểm soát tài sản getters và setters tạo ra một thông điệp Windows để yêu cầu kiểm soát cửa sổ bản địa cho giá trị tài sản. Bạn sẽ nhận được một kaboom trên những vì tài sản xử lý không còn giá trị. Đáng chú ý cũng là thiết lập thuộc tính Text cập nhật giá trị được lưu trữ nhưng cũng tạo ra một thông báo Window để cập nhật điều khiển gốc. Kaboom ở đây.

Tôi cho rằng đây chỉ là mối quan tâm chung, không bao giờ sử dụng mã như vậy trong chương trình của bạn. Vâng, bạn sẽ tìm ra đủ nhanh.

+0

Thx, câu trả lời hay nhất. –

1

Kịch bản debugger làm cho tôi nghĩ rằng những gì bạn làm là không đáng tin cậy, để kiểm tra nó, bạn ít nhất nên cố gắng này:

formDlg.Dispose(); 
Application.DoEvents(); 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 
string sUserEntered = box.Text; // After parent Dispose'd! 
+0

OK Tôi đã thử điều đó, nó vẫn "hoạt động". Các biến formDlg và hộp vẫn nằm trong phạm vi nên tôi không mong đợi GC sẽ ảnh hưởng đến các đối tượng của chúng. Dù sao cũng cảm ơn. –

+0

@Conrad: Tôi vẫn còn nghi ngờ, tại sao văn bản sẽ biến mất trong trình gỡ lỗi? –

+0

Tôi đã làm một số thử nghiệm và văn bản không biến mất với tất cả các biến thể mà tôi đã thử. Cho đến khi tôi đặt giá trị văn bản từ điều khiển vào thuộc tính công khai, tôi không thể lấy lại giá trị văn bản cho biểu mẫu chính của tôi - xem câu trả lời của tôi bên dưới. – IAbstract

2

Bạn có thể sử dụng 'sử dụng' tuyên bố để đảm bảo một đối tượng bị xử lý khi bạn đã thực hiện xong:

using(Form frmDialog = new Form()) 
{ 
    //Do stuff 
} 

frmDialog sẽ được xử lý khi khối đã chạy.

+0

Không thực sự thay đổi câu hỏi của mình. So sánh chuỗi 'string sUserEntered = box.Text;' sẽ xuất hiện sau khối sử dụng. – Zyphrax

+0

Vâng, đó là cách chữa trị tốt hơn so với phương thức ShowAndDispose(). –

+1

@ Zyphrax, không, nó sẽ giải quyết vấn đề của OP về việc quên Dispose và dĩ nhiên là mã box.Text sẽ đi vào bên trong sử dụng. –

0

tôi đặt giá trị sUserEntered thành một tài sản công cộng để nó có thể được truy cập:

public string UserInput 
    { 
     get; 
     set; 
    } 

    public frmDialog() 
    { 
     // 
     // The InitializeComponent() call is required for Windows Forms designer support. 
     // 
     InitializeComponent(); 

     // 
     // TODO: Add constructor code after the InitializeComponent() call. 
     // 
    } 

    void Button1Click(object sender, EventArgs e) 
    { 
     UserInput = userInput.Text; 
     this.Dispose(); 
    } 

Sau đó, trong mainform tôi:

 using (dialog = new frmDialog()) 
     { 
      dialog.ShowDialog(); 
      stringUserInput.Text = dialog.UserInput; 
     }; 
+0

Thx, tôi biết tôi có thể làm điều đó, tạo ra một lớp học hoàn toàn mới là rất nhiều thêm mã hơn tôi muốn. –

0

Nó xảy ra với tôi, tôi có thể tạo & sử dụng lớp bắt nguồn từ biểu mẫu với phương thức BeginShowDialog() gọi phương thức ShowDialog() và phương thức EndShowDialog() gọi Dispose(). Các "Bắt đầu" trong tên phương pháp sẽ làm cho sự cần thiết cho "End" gọi rõ ràng hơn.

Tôi nhớ sự hủy diệt quyết định của C++ đối với người dân địa phương khi rời khỏi phạm vi.

+0

Bạn vẫn phải quấn nó trong một khối thử/cuối cùng, vì vậy mức tăng sử dụng là gây tranh cãi. –

+0

Tôi sẽ bỏ qua thử/cuối cùng. Trong trường hợp không bao giờ xảy ra trong thế giới thực mà ShowDialog() ném, tôi sẽ sống với sự rò rỉ tài nguyên. –

+0

Tôi không đồng ý rằng "sử dụng" "giải quyết" vấn đề tôi muốn giải quyết, mà không bao giờ quên, đối với hàng trăm lớp tôi sử dụng, khi nào/liệu mỗi người có cần phải được xử lý hay không. Nếu tôi không nhớ điều đó, thì tôi sẽ không nhớ sử dụng "sử dụng" cho lớp đó tốt hơn là tôi sẽ nhớ gọi Dispose(). –

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