我很高兴编写了一个相当不错的项目,在运行时没有表现出任何奇怪的问题。因此,我决定运行静态代码分析工具(我使用的是Visual Studio 2010)。结果发现违反了规则CA2000
,如下所示:
警告-CA2000:Microsoft.Reliability:在方法'Bar.getDefaultFoo()'中,在所有引用到它的范围之前调用System.IDisposable.Dispose对象'new Foo()'。
引用的代码如下所示:
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,我也去了stackoverflow。找到了这篇文章。创建对象后没有需要执行的操作。我只需要返回对它的引用。但是,我已经尝试应用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()' 中,在所有引用超出作用域之前调用 System.IDisposable.Dispose 对象'result'。%%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。