Câu hỏi Tại sao Visual Studio IDE đôi khi khởi tạo đối tượng "this.components" và các lần khác không?


Gần đây tôi đã nhận thấy một số hành vi với Visual Studio Designer (C #) mà tôi không hiểu và đã tự hỏi nếu ai đó có thể làm rõ ...

Một trong số các Biểu mẫu Windows của tôi, dòng đầu tiên của nhà thiết kế tạo ra mã đọc;

this.components = new System.ComponentModel.Container();

Khi trường hợp này xảy ra, phương thức vứt bỏ, trong cùng một tệp thiết kế đó, phương thức vứt bỏ đặt hai cuộc gọi "Vứt bỏ" trong trường hợp "nếu" điều kiện như sau;

    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
            base.Dispose(disposing);
        }
    }

tức là Không có gì được gọi trừ khi xử lý là đúng, các thành phần AND không phải là rỗng.

Trên một số biểu mẫu khác, dòng đầu tiên trong mã do nhà thiết kế tạo bị thiếu. Trong những trường hợp này, lệnh gọi cơ bản.Dispose nằm ngoài điều kiện "if" như vậy ...

    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

Tôi đã nhận thấy điều này trong khi theo dõi xuống một lỗi với một hình thức không đóng cửa, nơi this.components là null, nhưng cuộc gọi base.Dispose là bên trong điều kiện đó (tôi nghi ngờ mã thiết kế đã bị giả mạo nhưng đó là một câu chuyện khác.

Điều gì kiểm soát hành vi này?

(Một số hình thức trước đó trong dự án đã được tạo ra trong VS 2005 và bây giờ chúng tôi sử dụng VS 2008 - đầu mối?)


11
2018-02-17 04:24


gốc




Các câu trả lời:


Đây là hành vi tái sản xuất. Khi bạn tạo một biểu mẫu mới, nó bắt đầu với một bộ khung bao gồm lời gọi hàm tạo của this.components. Khi bạn thêm một thành phần (nói một Timer) và loại bỏ nó một lần nữa, nhà thiết kế tạo lại mã, bây giờ mà không cần gọi hàm tạo. Đó không phải là lỗi.

Fwiw, mã bộ xương được tạo bởi Common7\IDE\ItemTemplates\CSharp\Windows Forms\1033\Form.zip\form.designer.cs

Nhìn thấy lời gọi hàm base.Dispose () bên trong câu lệnh if () là một lỗi. Đó có thể là tự gây ra. Hoặc nó có thể là phiên bản beta của mã bộ xương. VS2005 có đúng không. Hãy kiểm tra thư mục ItemsTemplatesCache.


4
2018-02-17 18:25



Cảm ơn nobugz. Tôi đã có một cơ hội để thử kịch bản này trong VS2005 bây giờ quá. Tốt rồi. Tôi chỉ có thể giả định, như bạn nói, đây là "tự gây ra". - Stuart Helwig
"bây giờ không có lời gọi hàm tạo". Vì vậy, những gì các điểm trong (components != null) kiểm tra nếu không có components khởi tạo bất cứ đâu? Ai, khi nào và ở đâu khởi tạo components? BTW, đến đây từ VS2010, .NET4.0 - Fulproof
Dường như bạn có câu hỏi mới. Bạn có thể yêu cầu bằng cách nhấp vào nút Hỏi câu hỏi. - Hans Passant
@ HansPassant Vì vậy, chúng ta không nên lo lắng về nó vì GC giải phóng ví dụ Bộ hẹn giờ? - Thomas


6 năm sau và vấn đề này vẫn xảy ra. Tôi đã quản lý để theo dõi ít ​​nhất một nguyên nhân cho nó xảy ra.

Khi thử nghiệm nếu thành phần của bạn có một hàm tạo có một IContainer, System.ComponentModel.Design.Serialization.ComponentCodeDomSerializer lưu trữ một tham chiếu đến Kiểu IContainer cho dự án của bạn. Nếu sau đó bạn lưu một đối tượng cho một dự án khác trong cùng một giải pháp, hoặc có lẽ khi bạn đã thực hiện một số loại thay đổi khác trong dự án của mình, ComponentCodeDomSerializer không còn có thể tìm thấy hàm tạo như Loại IContainer không còn bằng Loại lưu trữ.

Nếu điều này xảy ra rất nhiều cho dự án của bạn, có một giải pháp rất xấu. Thêm điều này VB hoặc là C #  VisualStudioWorkaroundSerializer lớp học để giải pháp của bạn. Sau đó thêm thuộc tính DesignerSerializer(GetType(VisualStudioWorkaroundSerializer), GetType(CodeDomSerializer)) thành phần của bạn. Bất cứ khi nào thành phần của bạn được lưu, bộ nối tiếp tùy chỉnh này sẽ phát hiện sự cố, khắc phục sự cố và buộc bạn phải lưu lại bất cứ khi nào sự cố này sắp xảy ra.


3
2017-09-22 07:21





Thú vị trục trặc! Nó thực sự âm thanh như một lỗi trong một phiên bản của nhà thiết kế / templating. Tất nhiên, nếu bạn nghĩ rằng các mã thiết kế đã bị giả mạo, tất cả các cược là khá nhiều ra anyway ...

Tuy nhiên, trong VS2008, nó tạo ra phiên bản không chính xác:

if (disposing && (components != null))
{
    components.Dispose();
}
base.Dispose(disposing);

Vậy cơ sở Dispose(...)được gọi là. Tôi đã không có VS2005 tiện dụng để kiểm tra nó, không may. Tuy nhiên - nó không khởi tạo các thành phần cho đến khi nó có - khai báo là:

private System.ComponentModel.IContainer components = null;

Và sau đó nếu nó là cần thiết, nó được cư trú trong InitializeComponent:

private void InitializeComponent()
{
    this.components = new System.ComponentModel.Container();
    //...
}

Tôi đoán với cấu trúc này, nó chỉ phải duy trì InitializeComponent (và không phải là các lĩnh vực riêng của mình).


1
2018-02-17 04:57



Không, tôi là Marc. Tôi sẽ phải cố gắng ở nhà tối nay. Cảm ơn. - Stuart Helwig
"nếu bạn nghĩ rằng các mã thiết kế đã bị giả mạo" - đó là tôi bởi vì tôi không hiểu làm thế nào để bình tĩnh nó! - Fulproof


Tôi đã thấy điều này xảy ra, và đôi khi tôi cũng đã nhận được cảnh báo về từ phương thức Vứt bỏ về các thành phần hoặc không bao giờ được gán giá trị của nó hoặc không được xác định.

Tôi nghĩ đó là sự kết hợp của hai điều:

  1. Tạo mã hơi khác nhau giữa các phiên bản của Visual Studio
  2. Phương thức Dispose chỉ được tạo ra nếu không có một tệp nào đã có trong tệp, trong khi InitializeComponent (và các khai báo liên quan) được tạo ra mỗi lần

Điều này dẫn đến một phần InitializeComponent / declarationations là out-of-whack với phương thức Dispose.


0
2018-02-17 05:27



"giữa các phiên bản của Visual Studio" - đến đây từ việc tạo các ứng dụng Windows Forms mới trong VS2010, .NET4.0 mà không sử dụng bất kỳ phiên bản nào khác (mặc dù giao diện người dùng có VS2008 được cài đặt trên PC) - Fulproof