【发布时间】:2013-01-24 00:39:46
【问题描述】:
我很高兴编写了一个运行良好且在运行时不会出现任何异常的项目。所以我决定运行静态代码分析工具(我使用的是 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。找到this article。创建对象后,我不需要执行任何操作。我只需要返回对它的引用。但是,我尝试应用 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 变量这次违反了规则。因此,基本上,代码变得扭曲、更长、有点不合理、不必要的复杂,并且执行相同的操作,但速度较慢。
我还发现了this question,其中相同的规则似乎以类似的方式攻击有效代码。并且建议提问者忽略警告。我还阅读了this thread 和大量类似的问题。
有什么我错过的吗?规则是否被窃听/无关?我该怎么办?忽视?以某种神奇的方式处理?也许应用一些设计模式?
编辑:
在 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。
【问题讨论】:
-
旁注:虽然警告本身不适用(请参阅@ReedCopsey 答案),但请确保使用真正 getDefaultFoo 的任何代码实际上都会处理结果(并且真正的 IFoo 继承自 IDisposable)
-
我很确定。如果需要,对象的所有者负责对其进行适当的处置。不过感谢您的提示。
标签: c# design-patterns static-analysis idisposable