Как избавиться от предупреждения 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 настолько низок, что не стоит проверять его по умолчанию, но только в отдельных обзорах. После некоторого количества ложных срабатываний предупреждение больше не может считаться предупреждением, просто шум, который скрывает реальные предупреждения и, следовательно, делает код более вероятным ошибкой.