Как избавиться от объекта, который повторяется через его свойство Next?

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

MyObject begin = null;

try
{
    begin = GetFirst();

    while (begin != null)
    {
        MyObject next = begin.Next();
        // do something with begin
        begin.Dispose();
        begin = next;
    }
}
finally
{    
    if (begin != null)
    {
        begin.Dispose();
    }
}

Я получаю проблему анализа кода:

CA2202: Microsoft.Usage: объект 'begin' может быть размещен более одного раза в методе 'x()'. Чтобы избежать создания System.ObjectDisposedException, вы не должны вызывать Dispose более одного раза для объекта.

Любая идея, как я могу избавиться от этой ошибки, не подавляя ее?

3 ответа

Решение

Мне, конечно, кажется, что ваш последний блок кода не нужен. Если begin != nullтогда ваш while цикл должен был продолжаться, нет?

ОБНОВЛЕНИЕ: похоже, вы пытаетесь обеспечить последнее полученное значение для begin утилизируется в случае возникновения исключения. Попробуй это:

MyObject begin = GetFirst();

while (begin != null)
{
    MyObject next;
    using (begin)
    {
        next = begin.Next();
        // do something with begin
    }

    begin = next;
}

Обратите внимание, что в приведенном выше предложении на самом деле все еще может случиться, что вы в конечном итоге получите неразмещенный объект: последнее значение, присвоенное nextдо конца using блок. Этот сценарий не был рассмотрен в вашем первоначальном вопросе, поэтому я не рассмотрел его в приведенном выше предложении. Это то, что нужно учитывать, если это потенциальная проблема.

Похоже, что Code Analysis считает возможным возникновение исключения во время Dispose() метод. Если бы это было так, вы бы вошли в блок finally с уже расположенной, хотя и ненулевой ссылкой на begin,

Обратите внимание, что я бы предпочел этот подход @Dan, только если вы планируете завершить вызов begin.Dispose() в дополнительном отслеживании и обработке ошибок. ИМО, решение Дэна более элегантно.

Вот подход try-finally, который удаляет предупреждение:

MyObject begin = GetFirst();
MyObject next = null;

while (begin != null)
{
    try
    {
        next = begin.Next();
        // do something with begin
    }
    finally
    {
        begin.Dispose();
        begin = next;
    }
}

У вас, очевидно, есть какой-то механизм для идентификации первого элемента в цепочке, возможно, какой-то другой объект или какой-то статический объект, который хранит первый элемент?

Как в вашем коде, который изначально вызывает dispose:

GetFirst().Dispose();

Тогда единственная ответственность за метод dispose заключается в удалении текущего элемента и его дочерних элементов:

public void Dispose()
{
    if (Next() != null)
    {
        Next().Dispose();
    }
}

Это устраняет необходимость в цикле внутри метода dispose. Я также хотел бы взглянуть на шаблон утилизации

Другие вопросы по тегам