Как избавиться от предупреждения CA2000 при передаче собственности?

Следующий код генерирует два предупреждения CA2000 (среди прочего, но это не так).

public sealed class Item: IDisposable
{
    public void Dispose() {}
}

public sealed class ItemContainer
{
    public void Add(Item item)
    {
    }
}

public sealed class Test: IDisposable
{
    private ICollection<Item> itemCollection;
    private ItemContainer itemContainer;

    private void Add(Item item)
    {
        itemCollection.Add(item);
    }

    public void Initialize()
    {
        var item1 = new Item(); // no warning
        itemCollection.Add(item1);

        var item2 = new Item(); // CA2000: call Dispose on object item2
        Add(item2);

        var item3 = new Item(); // CA2000: call Dispose on object item3
        itemContainer.Add(item3);
    }

    public void Dispose() {}
}

Обратите внимание, что для элемента 1 не создается предупреждение. Кажется, Code Analysis предполагает, что ICollection возьмет на себя ответственность за элемент и, в конечном счете, избавит его.

Есть ли способ пометить мои методы Add, чтобы предупреждение исчезло?

Я ищу что-то похожее на ValidatedNotNullAttribute для CA1062.

Изменить: чтобы было ясно: это не мой настоящий код. В реальном коде все правильно настроено.

Просто CA не признает, что вызов метода Add переводит право собственности. Я бы хотел, чтобы он обрабатывал мои методы добавления таким же образом, как это относится к ICollection.Add.

Утилизация в той же области не является вариантом.

Ответы

Ответ 1

Я также спросил об этом на сайте connect.microsoft.com, и на это они ответили:

Вы можете обойти проблему, имея объект container/collection, который добавляет одноразовый объект, реализующий ICollection или ICollection <T> . Метод, который выполняет добавление, должен также иметь имя, начинающееся с "Добавить".

И конечно: когда класс Test реализует ICollection <Item> , тогда предупреждение уходит. Это приемлемое решение для рассматриваемого случая. Но все же остается открытым вопрос, что делать, когда нецелесообразно внедрять ICollection, чтобы указать передачу прав собственности.

public sealed class Test: IDisposable, ICollection<Item>
{
    public void Initialize()
    {
        var item1 = new Item(); // no warning
        itemCollection.Add(item1);

        var item2 = new Item(); // no warning
        ((ICollection<Item>)this).Add(item2);

        var item3 = new Item(); // no warning
        AddSomething(item3);
    }

    //... implement ICollection and Method AddSomething
}

Ответ 2

Вы хотите исправить код или просто подавить предупреждения? Подавление предупреждений является простым:

[SuppressMessage("Microsoft.Reliability",
                 "CA2000:DisposeObjectsBeforeLosingScope",
                 Justification = "Your reasons go here")]
public void Initialize()
{
    // ...
}

Ответ 3

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

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

public void Initialize()
 {
  var item1 = new Item(); // no warning
  itemCollection.Add(item1);

  var item2 = CreateItem(); // CA2000 no longer appears
  Add(item2);

  var item3 = new Item(); // CA2000: call Dispose on object item3
  itemContainer.Add(item3);
 }

 private Item CreateItem()
 {
  return new Item();
 }

Очевидно, что для метода CreateItem можно передать произвольные параметры для перехода к конструктору Item.

Изменить

Увидев, что Хенрик ответил, и ответ на Connect, все, что я могу сказать, это bletch. Там нет гарантии, что реализация ICollection также реализует IDisposable, и хотя его опубликованный пример реализует IDisposable, очевидно, что не требуется закрывать анализ кода (я был бы в порядке, если бы вам пришлось реализовать оба). Класс, реализующий ICollection, но не реализующий IDisposable, вряд ли будет иметь дело с удалением содержащихся объектов правильно.

Ответ 4

Ну, конечно, первое, что нужно сделать, это фактически удалить метод Dispose членов коллекции. Я предполагаю, что просто ошибка в примере, а не реальный код.

Кроме того, я бы просто подавил предупреждение. Я очень сильно считаю, что любое подавление:

  • Должно быть очень короткое пространство, поэтому оно не подавляет другой случай предупреждения, который является подлинной ошибкой.
  • Должен быть аннотирован комментарием, независимо от того, насколько мертв мозг, кажется, что предупреждение безопасно подавлять.

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