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

时间:2010-10-14 10:16:04

标签: c# visual-studio-2010 code-analysis

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

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

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

我正在为CA1062寻找类似于ValidatedNotNullAttribute的东西。

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

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

在同一范围内处置不是一种选择。

4 个答案:

答案 0 :(得分:10)

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

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

答案 1 :(得分:7)

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

在这种特殊情况下,如果您将对象创建代码移动到它自己的方法中,它返回新的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();
 }

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

修改

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

答案 2 :(得分:7)

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

您可以通过使添加一次性对象的容器/集合对象实现ICollection或ICollection&lt; T&gt;来解决该问题。执行添加的方法也必须具有以“添加”开头的名称。

当然,当类Test实现ICollection&lt; Item&gt;时,警告就会消失。对于相关案例,这是一个可接受的解决方案。但是,如果不适合实施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
}

答案 3 :(得分:1)

当然,首先要做的是让Dispose方法实际上清理集合的成员。我假设这只是示例中的错误,而不是真正的代码。

除此之外,我会压制警告。我强烈坚持任何压制:

  1. 应该是一个非常短的范围,所以它不会压制另一个警告的情况,这是一个真正的错误。
  2. 应该注释注释,无论多么明显的脑死亡,警告似乎是安全的。
  3. 那就是说,我认为对CA2000的分析是如此之差,以至于不值得在默认情况下进行检查,但仅限于偶尔的评论。在一定数量的误报之后,警告甚至不能再被视为警告,只是隐藏真实警告的噪音,从而使代码更容易出错。