Распорядиться или не распорядиться (CA2000) - PullRequest
13 голосов
/ 24 ноября 2010

Я включаю анализ кода в старом проекте.Большинство замечаний, которые я могу понять, приводит к тому, что CA2000: Утилизировать объекты до потери контекста трудно понять правильно.

Например, этот код со страницы ASP.Net:

private void BuildTable()
{
    HtmlTableRow tr = new HtmlTableRow();
    HtmlTableCell td = new HtmlTableCell();

    tr.Cells.Add(td);
    // add some controls to 'td'

    theTable.Rows.Insert(0, tr);
    // 'theTable' is an HtmlTable control on the page
}

Предоставляет сообщения CA:

CA2000: Microsoft.Reliability: В методе 'BuildTable ()' вызовите System.IDisposable.Dispose для объекта 'tr' до того, как все ссылки на него станутвне области видимости.

CA2000: Microsoft.Reliability: В методе 'BuildTable ()' объект 'td' расположен не по всем путям исключений.Вызовите System.IDisposable.Dispose для объекта 'td' до того, как все ссылки на него выйдут из области видимости.(и аналогичные сообщения об элементах управления, которые добавляются к этому 'td'.)

Я могу решить вторую проблему:

private void BuildTable()
{
    HtmlTableRow tr = new HtmlTableRow();
    HtmlTableCell td = new HtmlTableCell();

    try
    {
        tr.Cells.Add(td);
        // add some controls to 'td'

        td = null; // this line is only reached when there were no exceptions
    }
    finally
    {
        // only dispose if there were problems ('exception path')
        if (td != null) td.Dispose();
    }

    theTable.Rows.Insert(0, tr);
}

Но я не думаю, что этоможно разрешить сообщение о «tr».Я не могу избавиться от этого, потому что это все еще необходимо после завершения метода.

Или я что-то пропустил?

Кстати: изменение этого theTable.Rows.Insert в theTable.Rows.Add меняетсообщение CA «не размещено по всем исключениям путям»

Ответы [ 5 ]

10 голосов
/ 24 ноября 2010

Анализ кода не может полностью понять ваш код и просто предупреждает, если вы создаете одноразовый объект, который, кажется, не утилизируется.В вашем случае вы должны отключить предупреждение, потому что объект не должен быть утилизирован перед выходом из метода.Вы можете отключить предупреждения либо для всего проекта, настроив набор правил анализа кода, либо для каждого метода, имеющего это предупреждение, когда очевидно, что анализ кода неправильный.

При этом я рекомендую использоватьusing конструкция при работе с IDisposable объектами:

using (var tr = new HtmlTableRow()) {
  using (var td = new HtmlTableCell()) {
    tr.Cells.Add(td);
    theTable.Rows.Insert(0, tr);
  }
}

За исключением того, что этот код является бессмысленным, поскольку вы не хотите располагать строку и ячейку, которые вы только что добавили в таблицу.

2 голосов
/ 04 июня 2011

этот код избавит от обоих предупреждений (Я использую (HtmlTable) для имитации вашего глобального члена HtmlTable ...):

using (HtmlTable theTable = new HtmlTable())
{
    HtmlTableRow tr = null;
    try
    {
        HtmlTableCell td = null;

        try
        {
            td = new HtmlTableCell();

            // add some controls to 'td'


            tr = new HtmlTableRow();
            tr.Cells.Add(td);

            /* td will now be disposed by tr.Dispose() */
            td = null;
        }
        finally
        {
            if (td != null)
            {
                td.Dispose();
                td = null;
            }
        }

        theTable.Rows.Insert(0, tr);

        /* tr will now be disposed by theTable.Dispose() */
        tr = null;
    }
    finally
    {
        if (tr != null)
        {
            tr.Dispose();
            tr = null;
        }
    }
}

но я думаю, вы рассмотрите возможность использования подхода, использующего подфункции, чтобы сделать код более понятным:

    private static void createTable()
    {
        using (HtmlTable theTable = new HtmlTable())
        {
            createRows(theTable);
        }
    }

    private static void createRows(HtmlTable theTable)
    {
        HtmlTableRow tr = null;
        try
        {
            tr = new HtmlTableRow();
            createCells(tr);

            theTable.Rows.Insert(0, tr);

            /* tr will now be disposed by theTable.Dispose() */
            tr = null;
        }
        finally
        {
            if (tr != null)
            {
                tr.Dispose();
                tr = null;
            }
        }
    }

    private static void createCells(HtmlTableRow tr)
    {
        HtmlTableCell td = null;

        try
        {
            td = new HtmlTableCell();

            // add some controls to 'td'


            tr.Cells.Add(td);

            /* td will now be disposed by tr.Dispose() */
            td = null;
        }
        finally
        {
            if (td != null)
            {
                td.Dispose();
                td = null;
            }
        }
    }
2 голосов
/ 24 ноября 2010

Я думаю, что вы только что показали, что правило CA2000 не очень полезно на большинстве баз кода. Насколько я знаю,

  • Dispose на HtmlTableRow не делает ничего полезного, если оноиспользуется внутри дизайнера пользовательского интерфейса;Я никогда не видел, чтобы кто-нибудь вызывал утилиту на элементах управления Asp.net.(Winforms / WPF - это другой случай)
  • Вы храните ссылку на td внутри таблицы, поэтому вам не следует ее утилизировать.

Поскольку оба вышеперечисленных слова очень распространеныв нормальном коде я не вижу, чтобы правило CA2000 имело значение для большинства баз кодов - существует столько ложных срабатываний , что вы, скорее всего, пропустите в 1 из 50 случаевкогда это настоящая проблема.

1 голос
/ 30 декабря 2010

Добавьте элемент управления в коллекцию непосредственно после его создания, но перед тем, как что-либо делать с элементом управления.

HtmlTableRow tr = new HtmlTableRow();
theTable.Rows.Insert(0, tr);

HtmlTableCell td = new HtmlTableCell();
tr.Cells.Add(td);

// add some controls to 'td'

Поскольку не может быть исключения между созданием и добавлением / вставкой элемента управления вСбор нет необходимости пробовать / ловить.Если после добавления элемента управления в коллекцию возникает исключение, страница будет его удалять.Вы не получите CA2000 таким образом.

0 голосов
/ 13 декабря 2012

Если вы считаете, что анализ кода неправильный (мне пришло в голову, что он попросил вызвать Dispose для объекта, который не реализует IDisposable), или вы не чувствуете, что необходимо удалить этот объект, вы всегда можете подавитьэто сообщение, как это.

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000: DisposeObjectsBeforeLosingScope")]
public static IDataReader RetrieveData(string conn, string sql)
{
    SqlConnection connection = new SqlConnection(conn);
    SqlCommand command = new SqlCommand(sql, conn);
    return command.ExecuteReader(CommandBehavior.CloseConnection);
    //Oops, I forgot to dispose of the command, and now I don't get warned about that.
}
...