2010-10-14 60 views
14

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

请注意,没有为item1生成警告。看起来,代码分析假定ICollection将承担该项目的责任,并最终处置它。

有没有一种方法,以纪念我的Add方法,从而使警报消失?

我在找寻类似于CA1062的ValidatedNotNullAttribute

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

这只是CA不承认,打到我Add方法转移所有权。 我希望它能够像处理ICollection.Add一样对待我的Add方法。

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

回答

6

我也问了这个在connect.microsoft.com而这也正是他们回答:

您可以通过具有容器/集合对象,增加了一次性对象实现的ICollection或ICollection的<牛逼>解决该问题。执行添加的方法也必须具有以“添加”开头的名称。

当然,当class 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 
} 
+0

接受我自己的答案,因为这是我在这种情况下所做的:在已实现IDisposable的类上实现ICollection。我完全同意Damien的观点:如果CA需要IDisposable和ICollection,那将更有意义。 – Henrik 2010-10-23 07:19:38

+0

有什么办法可以通过索引在一次性物品字典上实现类似的东西吗? – Dave 2018-03-02 10:20:34

9

你想修复代码还是只是压制警告?抑制警告很简单:

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

我宁愿看到这样的理由,所以stylecop。 – annakata 2010-10-14 10:41:04

+1

@annakata:我也会这样编辑它来包括它...... – LukeH 2010-10-14 10:45:07

+1

我宁愿不压制警告。如果该方法稍后修改,我希望在适当的时候发出警告。 – Henrik 2010-10-14 10:47:14

1

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

除此之外,我只是压制警告。我非常强烈地认为,任何压制:

  1. 应该是一个非常短的范围,所以它不会抑制另一个是真正的错误警告的情况。
  2. 应该注释一个评论,不管死亡如何明显,看起来警告是安全的压制。

这就是说,我认为CA2000的分析很差,不值得让它默认检查,但只是在偶尔的评论。经过一定数量的误报后,警告甚至不会再被视为警告,只是噪声隐藏了真实的警告,因此使代码更有可能成为越野车。

6

我知道这是示例代码,所以这个解决方法是否会在你的真实代码中工作,我不能说。

在这种特殊情况下,如果您将对象创建代码移入其自己的方法中,并返回新的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的回答,并在连接反应,我可以说的是bletch。不能保证ICollection实现也实现了IDisposable,虽然他的发布示例确实实现了IDisposable,但显然这并不需要关闭代码分析(如果必须实现这两者,我还是会有点不错)。一个实现ICollection但不实现IDisposable的类很难处理正确处理包含的对象。

+0

但是在这种情况下,即使删除了Add(item2)并且item2可验证地不处理,警告也不会出现。所以我可能只是压制警告。 – Henrik 2010-10-18 12:17:07

+0

@亨利克 - 我花的时间越多,我越感到困惑。不能保证任何特定的ICollection实现将正确地处理添加到它的项目,所以我一直在想,为什么我们不能*获取项目1的CA2000。 – 2010-10-19 06:28:26

+0

获得此答案的赏金。这在CreateItem方法内部将该项目添加到集合以确保它已丢弃的情况下可能很有用。 – Henrik 2010-10-23 07:18:46