我有以下代码: 一次性类,包含两个一次性成员。 其中一个是使用new()方法初始化,另一个是使用静态工厂方法。 我还有静态代码analisys规则,CA2213为错误。
public class DisposableClass : IDisposable
{
private WebClient m_DisposableMember1;
public WebClient DisposableMember1
{
get
{
if (m_DisposableMember1 == null)
{
m_DisposableMember1 = new WebClient();
}
return m_DisposableMember1;
}
}
private WebClient m_DisposableMember2;
public WebClient DisposableMember2
{
get
{
if (m_DisposableMember2 == null)
{
m_DisposableMember2 = Factory.Create();
}
return m_DisposableMember2;
}
}
#region Finalize/Dispose Pattern
private bool m_IsDisposed = false;
//Implement IDisposable.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~DisposableClass()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (!m_IsDisposed)
{
if (disposing)
{
DisposableMember1.Dispose();
// DisposableMember2 in not disposed and not notified by fxCop
}
m_IsDisposed = true;
}
}
#endregion Finalize/Dispose Pattern
}
这是一个简单的工厂类:
public static class Factory
{
public static WebClient Create()
{
return new WebClient();
}
}
当我调用DisposableMember1属性的Dispose()方法时,我得到了CA2213。 当我调用m_DisposableMember1成员的Dispose()方法时,我没有收到此错误。
此外,我没有收到m_DisposableMember2的错误(使用静态工厂初始化),并且没有处理。
有人熟悉这个问题吗?什么可能导致这种行为?
答案 0 :(得分:2)
CA2213在识别应该处置的字段方面并不是特别积极。在其他潜在问题中,它只考虑从构造函数调用直接赋值的字段。通过属性或构造函数调用之外的源分配字段值不会导致目标字段被规则包含在“应该处置”字段池中。
答案 1 :(得分:1)
你期待这个工具的智慧有点太多了。该属性是该领域的别名,这对人眼来说是显而易见的。它需要非常复杂的分析才能让工具看到它。 FxCop只是没有那种马力。你的代码实际上是有问题的。如果客户端代码从未使用该属性,那么您将创建WebClient对象并立即将其处置。请改用字段,测试null和Dispose()。
第二个字段的问题可能是由于需要使用该工具来避免不必要的警告。它只会抱怨它是否可以绝对肯定地确定该字段是否已被初始化。这里同样缺乏智能,它无法分辨出工厂总是返回非空引用。只有当它看到在类本身中使用的构造函数时才能确保该字段需要被处理。
这是一个很好的工具,并不完美。