【发布时间】:2011-05-24 14:16:07
【问题描述】:
我在这里需要一些建议,希望有人可以帮助我。我有以下类结构(简化):
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 类的所有“CreateFooX()”方法上收到警告 CA2000。此警告提供以下消息:
“Microsoft. 可靠性:在方法 'FooProvider.GetFooX()' 中,在对象 'bar' 的所有引用超出范围之前调用 System.IDisposable.Dispose。”
Microsoft 建议不要禁止显示此警告,但我不确定它是否会警告代码中的实际问题。确实,在我们考虑的任何 'CreateFooX()' 方法中,在超出范围之前不会释放 'bar',但对它的引用仍然存在于 'FooX' 对象中,该对象最终将被释放,并反过来处理释放 '吧”。
我是否对 Dispose 模式的工作方式理解有误,并且我的代码存在一些根本缺陷,还是应该直接取消此警告?
编辑
由于某些 cmets,我尝试将工厂方法修改为以下内容:
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;
}
}
...
}
但我仍然收到同样的警告。我想这只是一个误报,我可以放心使用它。
感谢您的建议。
【问题讨论】:
-
不知道你是否为了简洁而省略了它,但不要忘记在 FooBase 中包含一个终结器,以便在代码中不显式调用 Dispose 时实际调用它。
-
是的,我省略了它。不过还是谢谢你的提醒。
-
@Massif, @InBetween:如果
FooBase只处理托管资源,而不直接 处理任何非托管资源,那么终结器应该是完全没有必要的。 -
@LukeH:你是绝对正确的。我应该指出它确实处理非托管资源,但它与问题没有直接关系,所以我没有提到它。
-
我也讨厌这种误报,并在这里开票:connect.microsoft.com/VisualStudio/feedback/details/779134。如果您愿意,请投票。
标签: c# .net code-analysis