Анализ кода Предупреждение об утилизации формы - PullRequest
1 голос
/ 10 января 2012

У меня есть пара статических методов, которые преобразуют форму в элемент управления (показано ниже). Анализатор помечает оба флага, заявляя: «CA2000: Microsoft.Reliability: В методе« ... »объект« форма »расположен не по всем путям исключений. Вызовите System.IDisposable.Dispose для объекта« форма »перед всеми ссылками на него. вне области. " Подобное помечено для tabPage.

ПРИМЕЧАНИЕ: для тех, у кого нет Enterprise Edition и меню Analyzer, это очень похоже на вывод FxCop.

Мне не ясно, что мне делать. Если new не удастся, будет выдано исключение. Где моя возможность позвонить Dispose?

class Foo
{
  static public Form FormAsControl()
  {
    Form form = new Foo();

    form.TopLevel = false;
    form.FormBorderStyle = FormBorderStyle.None;
    form.Dock = DockStyle.Fill;
    form.Visible = true;

    return form;
  }

  static public TabPage FormAsTabPage()
  {
    Form form = Foo.FormAsControl();
    TabPage tabPage = new TabPage();

    tabPage.Text = form.Text;
    tabPage.Controls.Add(form);

    return tabPage;
  }

  ...
}

Ответы [ 5 ]

6 голосов
/ 10 января 2012

CA2000 неприятен, слишком много ложных предупреждений.FxCop недостаточно умен, чтобы знать, как работает класс Control.Его метод Dispose () только делает что-то полезное после , когда создается собственное окно управления.Только тогда будут неуправляемые ресурсы, которые можно было бы утилизировать.Но этого не произойдет до тех пор, пока возвращаемая вами TabPage не будет добавлена ​​в TabControl, а этот элемент управления в свою очередь добавляется в форму и вызывается метод Show () этой формы.Код, который мы не можем видеть (ни FxCop в этом отношении).Более того, они на самом деле do удаляются, даже когда есть исключение, когда собственное окно разрушается.

Вы можете подавить предупреждение, добавив try / catch в методы, чтобы вы могли вызыватьDispose () в блоке catch.Но это было бы ошибкой, оно просто добавляет ненужный код, который не делает ничего полезного во время выполнения.Используйте атрибут [SuppressMessage], чтобы избавиться от предупреждения.

2 голосов
/ 10 января 2012

Исходя из вашего кода, вы не только должны игнорировать предупреждение, но вы должны игнорировать предупреждение.

Наивной реализацией может быть

public Control FormAsControl()
{
    using (Form form = new Foo())
    {
        // Set properties
        return form;
    }
}

но тогда form будет удалено до того, как вызывающий сможет использовать его!

Обратите внимание, что я предполагаю, что вы подразумевали, что класс Foo является производным от Form, и что вы имели в виду FormAsControl, чтобы вернуть Control, а не Form.

1 голос
/ 10 января 2012

Мы можем узнать кое-что из методов CII RAII здесь:

class auto_disposer<C> : IDisposable where C : class
{
    public C Child { get; private set; }
    public auto_disposer(C c) { Child = c; }

    public void Dispose() { IDisposable d =  Child as IDisposable; if (d != null) d.Dispose(); }
    public C Release() { C retval = Child; Child = null; return retval; }
}

class Foo
{
     static public Form FormAsControl()
     {
         using (var ad = new auto_disposer<Foo>(new Foo())) {
             Form form = ad.Child;
             form.TopLevel = false;
             form.FormBorderStyle = FormBorderStyle.None;
             form.Dock = DockStyle.Fill;
             form.Visible = true;

             return ad.Release();
         }
     }

     // ...
}

Таким образом, , если какое-либо присваивание свойства вызывает исключение , объект по-прежнему правильно расположен.

1 голос
/ 10 января 2012

Исходя из вашего кода, вы сможете спокойно игнорировать это предупреждение.

0 голосов
/ 10 января 2012

Поймать исключение, вызвать Dispose, throw?

...