简体   繁体   English

VS2010代码分析期间的IDisposable和CA2000警告

[英]IDisposable and CA2000 warning during VS2010 Code Analysis

I need some advice here, I hope somebody can help me.我在这里需要一些建议,我希望有人可以帮助我。 I have the following class structure (simplified):我有以下 class 结构(简化):

public class Bar: IDisposable {...}

public abstract class FooBase: IDisposable
{
    Bar bar;
    bool disposed;

    internal FooBase(Bar bar)
    {
        this.bar=bar;
    }

    public void Dispose()
    {
         Dispose(true);
         GC.SupressFinalize(this);

    }

    protected void Dispose(bool disposing)
    {
         if (!this.disposed)
         {
             if (disposing)
             {
                 this.bar.Dispose();
             }

             this.disposed = true;
         }
    }
}

public FooA: Foo {...}
public FooB: Foo {...}

public static class FooProvider
{
    public static FooA GetFooA()
    {
       Bar bar = new Bar();
       ...
       return new FooA(bar);
    }

    public static FooB GetFooB()
    {
        Bar bar = new Bar();
        ...
        return new FooB(bar);
    }

    ...
}

When I run Code Analysis on this, I get Warnings CA2000 on all 'CreateFooX()' methods of the FooProvider class.当我对此运行代码分析时,我在 FooProvider class 的所有“CreateFooX()”方法上收到警告 CA2000。 This warning gives the following message:此警告提供以下消息:

"Microsoft. Reliability: In method 'FooProvider.GetFooX()', call System.IDisposable.Dispose on object 'bar' before all references to it are out of scope." “微软。可靠性:在方法 'FooProvider.GetFooX()' 中,在 scope 的所有引用之前调用 object 'bar' 上的 System.IDisposable.Dispose。”

Microsoft recommends to never suppress this warning but I'm not really sure its warning about a real problem in the code. Microsoft 建议永远不要抑制此警告,但我不确定它是否会警告代码中的实际问题。 True that 'bar' is not disposed before going out of scope in whatever 'CreateFooX()' method we consider but a reference to it lives on in the 'FooX' object which eventually will get disposed and will in turn take care of disposing 'bar'.确实,在我们考虑的任何 'CreateFooX()' 方法中,在离开 scope 之前,'bar' 都不会被处理,但对它的引用仍然存在于 'FooX' object 中,最终将被处理并反过来处理处理 '酒吧'。

Am I understanding something wrong about how the Dispose pattern should work and I have some fundamental flaw in my code or should I just suppress this warning?我是否对 Dispose 模式的工作方式理解有误,并且我的代码中有一些根本缺陷,还是应该直接取消此警告?

EDIT编辑

Due to some comments I tried modifying the factory methods to the following:由于一些评论,我尝试将工厂方法修改为以下内容:

public static class FooProvider
{
    public static FooA GetFooA()
    {
       Bar bar = null;

       try
       {
           bar =  new Bar();
           ...
           return new FooA(bar);
       }
       catch
       {
           if (bar != null) bar.Dispose();
           throw;
       }
    }

    ...
}

But I still get the same warning.但我仍然收到同样的警告。 I guess its just a false positive and I'm safe ingoring it.我想这只是一个误报,我可以安全地接受它。

Thanks for any advice.感谢您的任何建议。

This is a typical false positive on Code Analysis' part.这是代码分析部分的典型误报。 It really cannot understand the intrinsic situation of your code, so it throws a general answer at it.它真的无法理解你的代码的内在情况,所以它给出了一个普遍的答案。 Proceed with caution, but whenever you verify that you have a false positive, you can safely ignore it.请谨慎行事,但只要您确认您有误报,您就可以放心地忽略它。

That is not a false positive.这不是误报。 What if an exception is thrown after the Bar is created but before it is passed to the Foo constructor?如果在创建Bar之后但在将其传递给Foo构造函数之前抛出异常怎么办? I see several code paths where one or more objects might not be disposed of.我看到几个代码路径可能不会处理一个或多个对象。

Your disposable pattern seems a little off to me.你的一次性模式对我来说似乎有点不对劲。 I don't think you should be calling bar.Dispose in the FooBase class.我认为您不应该在 FooBase class 中调用 bar.Dispose。 For safety of the objects you are disposing and being able to safly call Dispose multiple time I would recoment this approach.为了您正在处理的对象的安全,并且能够多次安全地调用 Dispose,我会推荐这种方法。

  private bool _disposed;
  public void Dispose()
  {
     Dispose( true );
     GC.SuppressFinalize( this );
  }

  protected virtual void Dispose( bool disposing )
  {
     if ( disposing )
     {
        if ( !_disposed )
        {
           if ( Bar != null )
           {
              Bar.Dispose();
           }

           _disposed = true;
        }
     }
  }

As for the error, I think that this should take care of the static analysis warning.至于错误,我认为这应该照顾到 static 分析警告。 I implemented your code as follows in a test project, enabled all static analysis warnings without having an issue with warnings.我在一个测试项目中按如下方式实现了您的代码,启用了所有 static 分析警告,而没有出现警告问题。

public class Bar : IDisposable
{
  private bool _disposed;
  public void Dispose()
  {
     Dispose( true );
     GC.SuppressFinalize( this );
  }

  protected virtual void Dispose( bool disposing )
  {
     if ( disposing )
     {
        if ( !_disposed )
        {
           _disposed = true;
        }
     }
  }
}

public abstract class FooBase : IDisposable
{
  public Bar Bar
  {
     get;
     set;
  }

  internal FooBase( Bar bar )
  {
     Bar = bar;
  }

  private bool _disposed;
  public void Dispose()
  {
     Dispose( true );
     GC.SuppressFinalize( this );
  }

  protected virtual void Dispose( bool disposing )
  {
     if ( disposing )
     {
        if ( !_disposed )
        {
           if ( Bar != null )
           {
              Bar.Dispose();
           }

           _disposed = true;
        }
     }
  }
}

public class FooA : FooBase
{
  public FooA( Bar bar )
     : base( bar )
  {
  }
}

public static class FooProvider
{
  public static FooA GetFooA()
  {
     Bar bar;
     using ( bar = new Bar() )
     {
        return new FooA( bar );
     }
  }
}

[TestClass]
public class UnitTest1
{
  [TestMethod]
  public void StaticAnalysisTest()
  {
     Assert.IsNotNull( FooProvider.GetFooA().Bar );
  }
}

I hope this is helpful.我希望这是有帮助的。

At least part of this problem isn't really a false positive, even if it's not necessarily a very useful issue detection.至少这个问题的一部分并不是真正的误报,即使它不一定是一个非常有用的问题检测。 To fix the remaining problem your edited version, you need to open the try block immediately after the bar assignment, not before it.要解决您编辑版本的剩余问题,您需要在bar分配之后立即打开try块,而不是在它之前。 eg :例如

Bar bar = new Bar();
try
{
    ///...            
    return new FooA(bar);
}
catch
{
    bar.Dispose();
    throw;
}

Unfortunately, after you make this change, you'll still get a CA2000 violation, which will probably be a false positive.不幸的是,在您进行此更改后,您仍然会遇到 CA2000 违规,这可能是误报。 That's because the rule doesn't check to see if you're placing bar into the state of the newly created FooA .这是因为该规则不会检查您是否将bar放入新创建的 FooA 的FooA中。 If it is going into state in the FooA , you can safely create a suppression for the violation.如果它进入 FooA 中的FooA ,您可以安全地为违规创建抑制。 However, if it's not going into state in FooA , you should dispose it in a finally clause instead of a catch clause.但是,如果它没有进入 FooA 中的FooA ,则应将其放置在finally子句而不是catch子句中。

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

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