我很高兴编写了一个运行良好且在运行时不会出现任何异常的项目。所以我决定运行静态代码分析工具(我使用的是 Visual Studio 2010)。结果发现违反了规则CA2000
,消息如下:
警告 - CA2000:Microsoft.Reliability:在方法“Bar.getDefaultFoo()”中,在对对象“new Foo()”的所有引用超出范围之前调用 System.IDisposable.Dispose。
引用的代码是这样的:
private static IFoo getDefaultFoo()
{
return (Baz.canIDoIt()) ? new Foo() : null;
}
我自己想:也许条件表达式破坏了逻辑(我的或验证者的)。改为:
private static IFoo getDefaultFoo()
{
IFoo ret = null;
if (Baz.canIDoIt())
{
retFoo = new Foo();
}
return ret;
}
同样的事情又发生了,但现在该对象被称为retFoo
. 我用谷歌搜索,我已经 msdn'ed,我已经 stackoverflow'ed。找到这篇文章。创建对象后,我不需要执行任何操作。我只需要返回对它的引用。但是,我尝试应用 OpenPort2 示例中建议的模式。现在代码如下所示:
private static IFoo getDefaultFoo()
{
Foo tempFoo = null;
Foo retFoo = null;
try
{
if (Baz.canIDoIt())
{
tempFoo = new Foo();
}
retFoo= tempFoo;
tempFoo = null;
}
finally
{
if (tempFoo != null)
{
tempFoo.Dispose();
}
}
return retFoo;
}
再次出现相同的消息,但tempFoo
这次变量违反了规则。所以基本上,代码变得扭曲,更长,有点不合理,不必要的复杂,并且做同样的事情,但速度更慢。
我也发现了这个问题,其中相同的规则似乎以类似的方式攻击有效代码。并且建议提问者忽略警告。我也读过这个线程和大量类似的问题。
有什么我错过的吗?规则是否被窃听/无关?我该怎么办?忽视?以某种神奇的方式处理?也许应用一些设计模式?
编辑:
在 Nicole 的请求之后,我以我也尝试使用的形式提交了整个相关代码。
public class DisposableFooTest
{
public interface IFoo
{
void bar();
}
public class Foo : IFoo, IDisposable
{
public void bar()
{
Console.Out.WriteLine("Foo baring now");
}
public void Dispose()
{
// actual Dispose implementation is irrelevant, or maybe it is?
// anyway I followed microsoft dispose pattern
// with Dispose(bool disposing)
}
}
public static class Baz
{
private static bool toggle = false;
public static bool canIDoIt()
{
toggle ^= true;
return toggle;
}
}
private static IFoo getDefaultFoo()
{
IFoo result = null;
try
{
if (Baz.canIDoIt())
{
result = new Foo();
}
return result;
}
catch
{
if (result != null)
{
(result as IDisposable).Dispose();
// IFoo does not inherit from IDisposable, hence the cast
}
throw;
}
}
public static void Main()
{
IFoo bar = getDefaultFoo();
}
}
分析报告包含以下内容:
`CA2000:Microsoft.Reliability:在方法“DisposableFooTest.getDefaultFoo()”中,在对对象“result”的所有引用超出范围之前调用 System.IDisposable.Dispose。%%projectpath%%\DisposableFooTest.cs 44 测试
编辑2:
以下方法解决了 CA2000 问题:
private static IFoo getDefaultFoo()
{
Foo result = null;
try
{
if (Baz.canIDoIt())
{
result = new Foo();
}
return result;
}
finally
{
if (result != null)
{
result.Dispose();
}
}
}
不幸的是,我不能走那条路。更重要的是,我更希望遵循面向对象的原则、良好实践和指南来简化代码,使其具有可读性、可维护性和可扩展性。我怀疑有人会按预期阅读它:如果可能,给 Foo ,否则为 null 。