![](/img/trans.png)
[英]VS2010: Code analysis warning CA2000. Object is not disposed along all exception paths
[英]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.