转让所有权后如何摆脱CA2000警告?

Hen*_*rik 15 c# code-analysis visual-studio-2010

以下代码生成两个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() {}
}
Run Code Online (Sandbox Code Playgroud)

请注意,item1没有生成警告.似乎,代码分析假定ICollection遗嘱将对该项目负责并最终处置它.

有没有办法标记我的Add方法,以便警告消失?

我正在寻找类似于ValidatedNotNullAttributeCA1062的东西.

编辑:说清楚:这不是我的真实代码.在真实的代码中,一切都妥善处理.

只是CA无法识别对我的Add方法的调用转移所有权.我希望它以与处理相同的方式处理我的Add方法ICollection.Add.

处置相同的范围不是一种选择.

Luk*_*keH 11

您想修复代码还是只是禁止警告?抑制警告很简单:

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

  • 我更愿意看到有正当理由,所以风格也会如此. (2认同)
  • 我宁愿不抑制警告。如果该方法后来被修改,我想在适当的时候得到一个警告。 (2认同)
  • @Henrik:CA2000分析规则似乎相当粗糙,过于热心.据我所知,保持它快乐的唯一方法是在同一范围内实际处理你的IDisposable(有一些奇怪的例外,例如你的例子中`item1`的行为). (2认同)

Dam*_*ver 8

我知道这是示例代码,因此这种解决方法是否适用于您的实际代码,我不能说.

在这种特殊情况下,如果将对象创建代码移动到它自己的方法中,则返回新的Item,然后警告将消失,例如更改:

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();
 }
Run Code Online (Sandbox Code Playgroud)

显然,CreateItem方法可以传递任意参数传递给Item构造函数.

编辑

看过Henrik的回答,以及对Connect的回应,我只能说是bletch.不能保证ICollection实现也实现了IDisposable,虽然他发布的示例确实实现了IDisposable,但显然不需要关闭代码分析(如果你必须同时实现两者,我会有所帮助).实现ICollection但未实现IDisposable的类极不可能正确处理包含的对象.


Hen*_*rik 8

我也在connect.microsoft.com上问了这个,这就是他们回答的问题:

您可以通过使添加一次性对象的容器/集合对象实现ICollection或ICollection <T>来解决此问题.执行Add的方法也必须具有以"Add"开头的名称.

当然,当类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
}
Run Code Online (Sandbox Code Playgroud)