以下代码对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通过执行以下两项操作来对此进行响应:

  • 降低CA2000的敏感性,以便仅在最明显的情况下触发。这似乎是合理的,因为像第一行这样的明显情况比起较晦涩的情况更可能是错误,并且更容易修复。
  • 将CA2000排除在推荐的代码分析规则之外;请注意,其“扩展正确性”规则集不再包含CA2000。

  • 与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/

    10-10 07:35