Почему Visual Studio IDE иногда инициализирует объект "this.components", а иногда нет? - PullRequest
11 голосов
/ 17 февраля 2009

Я недавно заметил некоторое поведение с Visual Studio Designer (C #), которое я не понимаю, и мне было интересно, если кто-то может прояснить ...

Одна из моих Windows Forms, первая строка кода, сгенерированного дизайнером, гласит:

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

В этом случае метод dispose в том же файле конструктора метод dispose помещает два вызова «Dispose» в условие case «if» следующим образом;

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

т.е. Ничего не вызывается, если удаление не является истинным, а компоненты не равны нулю.

В некоторых других формах эта первая строка в сгенерированном дизайнером коде отсутствует. В этих случаях вызов base.Dispose находится вне условия "if" как такового ...

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

Я заметил это, когда выслеживал ошибку с закрытой формой, где this.components был нулевым, но в этом условии был вызов base.Dispose (я подозреваю, что код конструктора был подделан, но это другая история).

Что контролирует это поведение?

(Некоторые более ранние формы в проекте были созданы в VS 2005, и теперь мы используем VS 2008 - подсказка?)

Ответы [ 4 ]

4 голосов
/ 17 февраля 2009

Это воспроизводимое поведение. Когда вы создаете новую форму, она начинается со скелета, который включает вызов конструктора this.components. Когда вы затем добавляете компонент (скажем, Timer) и удаляете его снова, дизайнер регенерирует код, теперь без вызова конструктора. Это не ошибка.

Fwiw, код скелета генерируется Common7\IDE\ItemTemplates\CSharp\Windows Forms\1033\Form.zip\form.designer.cs

Просмотр вызова base.Dispose () внутри оператора if () является ошибкой. Это может быть вызвано самим собой. Или это может быть бета-версия кода скелета. VS2005 делает это правильно. Проверьте папку ItemsTemplatesCache.

3 голосов
/ 22 сентября 2015

6 лет спустя и эта проблема все еще возникает. Мне удалось отследить хотя бы одну причину этого.

При тестировании, если ваш компонент имеет конструктор, который принимает IContainer, System.ComponentModel.Design.Serialization.ComponentCodeDomSerializer кэширует ссылку на тип IContainer для вашего проекта. Если вы затем сохраните объект для другого проекта в том же решении или, возможно, когда вы внесли некоторые другие типы изменений в ваш проект, ComponentCodeDomSerializer больше не сможет найти конструктор, так как тип IContainer больше не равен его кэшированному типу.

Если это часто происходит с вашим проектом, есть очень уродливый обходной путь. Добавьте этот класс VB или C # VisualStudioWorkaroundSerializer к вашему решению. Затем добавьте атрибут DesignerSerializer(GetType(VisualStudioWorkaroundSerializer), GetType(CodeDomSerializer)) к вашему компоненту. Каждый раз, когда ваш компонент сохраняется, этот настраиваемый сериализатор будет обнаруживать проблему, исправлять ее и заставлять вас сохранять ее снова, когда эта проблема вот-вот возникнет.

1 голос
/ 17 февраля 2009

Интересный глюк! Это действительно звучит как ошибка в одной версии дизайнера / шаблона. Конечно, если вы думаете, что код дизайнера был подделан, все ставки в любом случае в значительной степени отклонены ...

Однако в VS2008 он генерирует несомненно правильную версию:

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

Так называется база Dispose(...). К сожалению, VS2005 не пригодился для его тестирования. Однако - он не инициализирует компоненты, пока не должен - объявление:

private System.ComponentModel.IContainer components = null;

А затем , если необходимо, оно заполняется в InitializeComponent:

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

Я полагаю, что с помощью этой конструкции он должен поддерживать только InitializeComponent (а не сами поля).

0 голосов
/ 17 февраля 2009

Я видел, как это происходило, и я также иногда получал предупреждения от метода Dispose о компонентах, которые никогда не назначали свое значение или не определялись.

Я думаю, что это сочетание двух вещей:

  1. Немного отличается генерация кода между версиями Visual Studio
  2. Метод Dispose генерируется только в том случае, если его нет в файле, тогда как InitializeComponent (и связанные объявления) генерируются каждый раз

Это приводит к тому, что в разделе InitializeComponent / декларации не работает метод Dispose.

...