以下代码对Main的第一行(而不是第二行)产生了CA2000(“在失去作用域之前先放置对象”)冲突。我真的很想在第二行违反CA2000,因为这是我工作的大型代码库中经常发现的(显然是简化的)模式。
有谁知道为什么第二行不产生违规?
public static void Main()
{
new Disposable();
MakeDisposable();
}
private static Disposable MakeDisposable() { return new Disposable(); }
private sealed class Disposable : IDisposable
{
public void Dispose()
{
}
}
最佳答案
简短的答案是,CA2000损坏了,不太可能很快修复。请参阅this bug report,这几乎就是您的问题:
更长的答案是使CA2000正确是困难的。在Visual Studio的早期版本中,尤其是在2010年中,到处都发出了错误的CA2000警告,您无法采取任何措施使它们消失。在“堆栈溢出”中搜索有关数十个问题中的任何一个。
即使在您可以消除该警告的情况下,解决方法也比仅将其保留在原处更糟。问题是,在这种情况下,就是您不希望在对象离开工厂方法范围之前就对其进行处置。除此之外,如果抛出异常,则执行。在这种情况下,该方法的返回值将丢失,并且调用者无法自行处置该对象。
不幸的是,试图弄清楚这一点意味着对已编译的IL进行程序流分析,以确定是否有任何代码路径(包括异常代码)允许对象泄漏。最终结果是,几乎任何您尝试从方法返回IDisposable
的情况都会产生错误。
Microsoft通过执行以下两项操作来对此进行响应:
与Roslyn编译器一起重写的还有FxCop之类的工具进行某些源代码级分析的能力,在这种情况下,可能更容易获得正确的分析结果。同时,普遍的共识是,只需关闭CA2000。
万一您感到好奇,可以进行一些测试,以确认当前(2013)CA规则仅在本地包含的本地构造的IDisposable
实例超出范围时才会触发。 IOW,对象不能留下对其进行new
编码的方法,否则CA将忽略它。这使我相信,CA根本不会深入分析其方法。除了尝试消除误报外,它还可能是通过削减一些昂贵的检查来加快CA流程的整体尝试的一部分,我认为这是在2010年至2012年之间发生的?
如果我在您的示例中添加一些内容,您会看到哪些明显的模式得到了警告:class Program
{
public static void Main()
{
new Disposable(); // CA2000
IDisposable x;
MakeDisposable(out x);
Test();
}
public static Disposable Test()
{
IDisposable z;
var x = MakeDisposable(out z);
var y = new Disposable(); // CA2000
return x;
}
private static Disposable MakeDisposable(out IDisposable result)
{
result = new Disposable();
new Disposable(); // CA2000
return new Disposable();
}
}
关于c# - 为什么FxCop不会为这种琐碎的类实例实例报告CA2000?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29594148/