Предложения о том, как избежать избавления от объекта дважды - PullRequest
4 голосов
/ 11 января 2012

У меня есть список одноразовых предметов, которые я добавляю в коллекцию, которая уже содержит ряд одноразовых предметов.Я обертываю код в блоке try ... finally, чтобы при возникновении исключения при копировании элементов из списка в коллекцию все объекты в списке корректно удалялись:

private static void LoadMenuItems(ApplicationMenu parent)
{
    List<ApplicationMenuItem> items = null;
    try
    {
        items = DataContext.GetMenuItems(parent.Id);
        foreach (var item in items)
        {
            parent.Items.Add(item);
        }
        items = null;
    }
    finally
    {
        if (items != null)
        {
            foreach (var item in items)
            {
                item.Dispose();
            }
        }
    }
}

Если после добавления ряда объектов в коллекцию возникает исключение, у меня будет ситуация, когда коллекция содержит некоторые удаленные объекты.Что может привести к тому, что эти удаленные объекты будут утилизированы снова в следующем блоке try ... catch:

try
{
    // Assume that menu.Items contains some items prior
    // to the call to LoadMenuItems.
    LoadMenuItems(menu);
}
catch
{
    // The Dispose() iterates through menu.Items calling 
    // Dispose() on each.
    menu.Dispose();
}

Итак, что я ищу, чтобы найти возможные решения, чтобы остановить вызов Dispose () дважды.Я имею в виду решение, но подумал, что дам его сообществу, чтобы посмотреть, есть ли альтернативы.

Ответы [ 2 ]

5 голосов
/ 11 января 2012

Что может привести к повторной утилизации этих утилизированных объектов

Что должно быть в порядке.Контракт на Dispose () очень специфичен: его можно вызывать несколько раз.


Но еще один способ избавиться от этого:

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

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

Большинство случаев, когда кто-то может беспокоиться о «случайной» утилизации объекта, возникает несколько раз, потому что существует путаница в отношении того, кто «владеет» рассматриваемым объектом, и такая путаница, вероятно, создаст другие проблемы в дополнение к повторной утилизации.В то время как можно было бы избежать того, чтобы само множественное удаление вызывало проблемы, используя метод удаления, использующий флаг, чтобы вторая попытка удаления вернулась безобидно, выполнение этого без устранения путаницы в отношении владения IDisposable не оставило бы более серьезные проблемы нерешенными.

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

  1. Ситуации, когда создание объекта завершается неудачей с частично созданным объектом;в то время как можно было бы определить политики относительно того, какие части частично сконструированного объекта отвечают за очистку, какие другие части, может быть проще просто попросить каждую часть, которой велено выполнять «экстренную» очистку, сообщить каждой части, о которой он знаетсделать так же, если это еще не сделано.В большинстве сценариев утилизации путаница, связанная с владением объектом, может привести к тому, что объекты будут удалены во время их использования, но если фабрика объектов выйдет из строя, это, как правило, означает, что никому не будет предоставлено никаких ссылок на объект.
  2. Ситуации, когда удаление объекта, который используется, является законным сценарием использования с предсказуемой семантикой.Например, некоторые источники данных имеют методы ожидания блокировки и явно указывают, что утилизация источника данных в то время, когда ожидает метод блокировки, приведет к тому, что этот метод завершится с ошибкой без дальнейшей задержки.В некоторых случаях вполне может быть так, что вытаскивание одноразового ресурса из-под задачи, которая его использует, является единственным способом для такой задачи открепиться.

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

...