C# 所有权转移时如何消除CA2000警告?

C# 所有权转移时如何消除CA2000警告?,c#,visual-studio-2010,code-analysis,C#,Visual Studio 2010,Code Analysis,下面的代码生成两个CA2000警告(除其他警告外,但这不是重点) 公共密封类项目:IDisposable { public void Dispose(){} } 公共密封类物品容器 { 公共作废添加(项目) { } } 公共密封类测试:IDisposable { 私人ICollection项目集合; 私有ItemContainer ItemContainer; 专用作废添加(项目) { itemCollection.Add(item); } 公共无效初始化() { var item1=new I

下面的代码生成两个CA2000警告(除其他警告外,但这不是重点)

公共密封类项目:IDisposable
{
public void Dispose(){}
}
公共密封类物品容器
{
公共作废添加(项目)
{
}
}
公共密封类测试:IDisposable
{
私人ICollection项目集合;
私有ItemContainer ItemContainer;
专用作废添加(项目)
{
itemCollection.Add(item);
}
公共无效初始化()
{
var item1=new Item();//无警告
itemCollection.Add(item1);
var item2=new Item();//CA2000:调用对象item2上的Dispose
增加(项目2);
var item3=new Item();//CA2000:对对象item3调用Dispose
itemContainer.Add(item3);
}
public void Dispose(){}
}
请注意,没有为item1生成任何警告。似乎,代码分析假设i收集将负责该项目并最终处置它

是否有方法标记我的
Add
方法,以便警告消失

我正在寻找类似于CA1062的
ValidatedNotNullAttribute

编辑:澄清一下:这不是我真正的代码。在实际代码中,所有内容都得到了正确的处理

只是CA没有意识到调用my
Add
方法会转移所有权。 我希望它以对待
ICollection.Add
的方式对待我的Add方法


在同一范围内处理不是一个选项。

您是要修复代码还是仅抑制警告?抑制警告很简单:

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

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

除此之外,我只想压制这个警告。我非常坚决地认为,任何镇压:

  • 应该是一个非常短的范围,所以它不会抑制另一个真正错误的警告案例
  • 应该加上注释,无论脑死亡多么明显,这一警告似乎是可以安全压制的
    也就是说,我认为CA2000的分析太差了,不值得默认检查,而只是偶尔检查一下。经过一定数量的误报后,警告甚至不能再被视为警告,只是隐藏真实警告的噪音,从而使代码更有可能出现错误。

    我知道这是示例代码,所以这个解决方法是否适用于您的真实代码,我不能说

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

    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方法可以传递任意参数以传递给项构造函数

    编辑


    看到亨里克的回答,以及《连线》上的回应,我只能说是布莱奇。不能保证ICollection实现也会实现IDisposable,虽然他发布的示例确实实现了IDisposable,但显然这并不是关闭代码分析的必要条件(如果必须同时实现这两个功能,我会觉得还行)。实现ICollection但未实现IDisposable的类不太可能正确处理包含对象的处理。

    我在connect.microsoft.com上也问过这个问题,他们的回答如下:

    您可以通过让添加一次性对象的容器/集合对象实现ICollection或ICollection来解决此问题。执行Add的方法的名称也必须以“Add”开头

    果然:当类测试实现ICollection时,警告就会消失。这是一个可以接受的解决方案。但当不适合实施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
    }
    
    公共密封类测试:IDisposable,ICollection
    {
    公共无效初始化()
    {
    var item1=new Item();//无警告
    itemCollection.Add(item1);
    var item2=new Item();//无警告
    添加(第2项);
    var item3=new Item();//无警告
    添加内容(第3项);
    }
    //…实现ICollection和方法AddSomething
    }
    
    我更希望看到有理由的警告,stylecop也是如此。我不希望抑制警告。如果这个方法后来被修改,我想得到一个警告,如果合适的话。@Henrik:CA2000分析规则似乎相当粗糙和过分热情。据我所知,让它高兴的唯一方法是在相同的范围内实际处理IDisPobles(除了一些奇怪的例外,例如示例中
    item1
    的行为)。许多代码分析规则都是粗糙的,过于热情。一个或两个是愚蠢的。我认为人们不能认为它们与编译器的警告一致,但作为一个非常不同的工具类。抑制消息是最后的手段。这里(几乎)没有不好的规定。如果您正在创建一个一次性对象,您应该有一个机制来处理它。但是在这种情况下,即使删除了Add(item2)并且item2未经验证也不会出现警告。所以我还是不提这个警告吧。@Henrik-我看这个的时间越长,我就越困惑。无法保证任何特定的ICollection实现都能正确处理添加到其中的项目,因此我一直想知道为什么我们没有为项目1获得CA2000。授予此答案奖金。如果CreateItem方法在内部将该项添加到集合中以确保该项已被释放,则这可能非常有用。接受我自己的答案,因为这就是我在本例中所做的:在已实现IDisposable的类上实现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
    }