简体   繁体   English

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

[英]How to get rid of CA2000 warning when ownership is transferred?

The following code generates two CA2000 warnings (among others, but that's not the point). 以下代码生成两个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() {}
}

Note that there is no warning generated for item1. 请注意,item1没有生成警告。 It seems, Code Analysis assumes the ICollection will take responsibility of the item and eventually dispose it. 似乎,代码分析假设ICollection将负责该项目并最终处置它。

Is there a way to mark my Add methods, so that the warning goes away? 有没有办法标记我的Add方法,以便警告消失?

I'm looking for something similar to ValidatedNotNullAttribute for CA1062. 我正在寻找类似于CA1062的ValidatedNotNullAttribute的东西。

Edit: to make it clear: this is not my real code. 编辑:说清楚:这不是我的真实代码。 In the real code, everything is properly disposed. 在真实的代码中,一切都妥善处理。

It's just that CA does not recognize that the call to my Add methods transfers ownership. 只是CA无法识别对Add方法的调用会转移所有权。 I would like it to treat my Add methods in the same way it treats ICollection.Add . 我希望它以与处理ICollection.Add相同的方式处理我的Add方法。

Disposing in the same scope is not an option. 处置相同的范围不是一种选择。

Do you want to fix the code or just suppress the warnings? 您想修复代码还是只是禁止警告? Suppressing the warnings is straightforward: 抑制警告很简单:

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

I know this is sample code, and so whether this workaround would work in your real code, I couldn't say. 我知道这是示例代码,因此这种解决方法是否适用于您的实际代码,我不能说。

In this particular case, if you move the object creation code into it's own method, that returns the new Item, then the warning will disappear, eg change: 在这种特殊情况下,如果将对象创建代码移动到它自己的方法中,则返回新的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();
 }

Obviously, the CreateItem method could be passed arbitrary parameters to pass to the Item constructor. 显然,CreateItem方法可以传递任意参数传递给Item构造函数。

Edit 编辑

Having seen Henrik's answer, and the response on Connect, all I can say is bletch . 看过Henrik的回答,以及对Connect的回应,我只能说是bletch There's no guarantee that an ICollection implementation also implements IDisposable, and whilst his posted example does implement IDisposable, apparently that's not required to shut up the code analysis (I'd have been somewhat okay if you had to implement both). 不能保证ICollection实现也实现了IDisposable,虽然他发布的示例确实实现了IDisposable,但显然不需要关闭代码分析(如果你必须同时实现两者,我会有所帮助)。 A class implementing ICollection but not implementing IDisposable is highly unlikely to deal with disposing of contained objects correctly. 实现ICollection但未实现IDisposable的类极不可能正确处理包含的对象。

I also asked this at connect.microsoft.com and this is what they answered: 我也在connect.microsoft.com上问了这个,这就是他们回答的问题:

You can workaround the issue by having the container/collection object that adds the disposable object implement ICollection or ICollection<T>. 您可以通过使添加一次性对象的容器/集合对象实现ICollection或ICollection <T>来解决此问题。 The method that performs the Add must also have name starting with "Add". 执行Add的方法也必须具有以“Add”开头的名称。

And sure enough: when class Test implements ICollection<Item>, then the warning goes away. 当然,当类Test实现ICollection <Item>时,警告就会消失。 This is an acceptable solution for the case in question. 对于相关案例,这是一个可接受的解决方案。 But it's still an open question what to do, when it's not appropriate to implement ICollection to indicate transfer of ownership. 但是,如果不适合实施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
}

Well of course the first thing to do is to actually have the Dispose method clean up the members of the collection. 当然,首先要做的是实际让Dispose方法清理集合的成员。 I'm assuming that's just an error in the example rather than the real code. 我假设这只是示例中的错误,而不是真正的代码。

Beyond that, I would just suppress the warning. 除此之外,我会压制警告。 I very strongly hold that any suppression: 我坚决认为任何压制:

  1. Should be of a very short scope, so it doesn't suppress another case of the warning that is a genuine mistake. 应该是一个非常短的范围,所以它不会压制另一个警告的情况,这是一个真正的错误。
  2. Should be annotated with a comment, no matter how brain-dead obvious it seems that the warning is safe to suppress. 应该注释注释,无论多么明显的脑死亡,似乎警告是安全的压制。

That said, I think the analysis of CA2000 is so poor as to not be worth having it checked by default, but only in occasional reviews. 也就是说,我认为对CA2000的分析是如此之差,以至于不值得在默认情况下进行检查,但仅限于偶尔的评论。 After a certain number of false-positives a warning can't even be considered a warning any more, just noise that's hiding real warnings and hence making code more likely to be buggy. 在一定数量的误报之后,警告甚至不能再被视为警告,只是噪音隐藏了真正的警告,因此使代码更容易出错。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM