繁体   English   中英

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

[英]IDisposable and CA2000 warning during VS2010 Code Analysis

我在这里需要一些建议,我希望有人可以帮助我。 我有以下 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);
    }

    ...
}

当我对此运行代码分析时,我在 FooProvider class 的所有“CreateFooX()”方法上收到警告 CA2000。 此警告提供以下消息:

“微软。可靠性:在方法 'FooProvider.GetFooX()' 中,在 scope 的所有引用之前调用 object 'bar' 上的 System.IDisposable.Dispose。”

Microsoft 建议永远不要抑制此警告,但我不确定它是否会警告代码中的实际问题。 确实,在我们考虑的任何 'CreateFooX()' 方法中,在离开 scope 之前,'bar' 都不会被处理,但对它的引用仍然存在于 'FooX' object 中,最终将被处理并反过来处理处理 '酒吧'。

我是否对 Dispose 模式的工作方式理解有误,并且我的代码中有一些根本缺陷,还是应该直接取消此警告?

编辑

由于一些评论,我尝试将工厂方法修改为以下内容:

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;
       }
    }

    ...
}

但我仍然收到同样的警告。 我想这只是一个误报,我可以安全地接受它。

感谢您的任何建议。

这是代码分析部分的典型误报。 它真的无法理解你的代码的内在情况,所以它给出了一个普遍的答案。 请谨慎行事,但只要您确认您有误报,您就可以放心地忽略它。

这不是误报。 如果在创建Bar之后但在将其传递给Foo构造函数之前抛出异常怎么办? 我看到几个代码路径可能不会处理一个或多个对象。

你的一次性模式对我来说似乎有点不对劲。 我认为您不应该在 FooBase class 中调用 bar.Dispose。 为了您正在处理的对象的安全,并且能够多次安全地调用 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;
        }
     }
  }

至于错误,我认为这应该照顾到 static 分析警告。 我在一个测试项目中按如下方式实现了您的代码,启用了所有 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 );
  }
}

我希望这是有帮助的。

至少这个问题的一部分并不是真正的误报,即使它不一定是一个非常有用的问题检测。 要解决您编辑版本的剩余问题,您需要在bar分配之后立即打开try块,而不是在它之前。 例如

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

不幸的是,在您进行此更改后,您仍然会遇到 CA2000 违规,这可能是误报。 这是因为该规则不会检查您是否将bar放入新创建的 FooA 的FooA中。 如果它进入 FooA 中的FooA ,您可以安全地为违规创建抑制。 但是,如果它没有进入 FooA 中的FooA ,则应将其放置在finally子句而不是catch子句中。

暂无
暂无

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

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