IDisposable在方法内创建并返回

问题描述 投票:15回答:4

我很高兴编写了一个很好的项目,并且在运行时没有任何奇怪之处。因此,我决定运行静态代码分析工具(我使用的是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。我用谷歌搜索,我已经搜索,我已经stackoverflow了。找到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和大量类似的问题。

我有什么想念的吗?规则是否错误/无关?我该怎么办?忽视?以某种magickal方式处理?也许应用一些设计模式?

编辑:

在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测试

Edit2:

以下方法解决了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。

我很高兴编写了一个很好的项目,并且在运行时没有任何奇怪之处。因此,我决定运行静态代码分析工具(我使用的是Visual Studio 2010)。结果表明,规则CA2000 ...

c# design-patterns static-analysis idisposable
4个回答
9
投票

这是一个误报。如果IFoo实现了IFoo,则无法返回IDisposable的适当实例,而没有代码分析工具警告您未正确处理它。


8
投票
这里的问题不是您的C#代码正在明确执行的操作,而是所生成的IL正在使用多个指令来完成C#代码中看起来像一个“步骤”的操作。

2
投票
静态分析基本上是出于以下原因而抱怨:

-1
投票
返回IDisposable对象时,如果值为null,则处理该对象并在方法中返回null-这应清除与“私有静态IFoo getDefaultFoo()”方法相关的“警告/建议”消息。 。当然,您仍然需要在调用例程中将对象作为IDisposable处理(使用或处置)。
© www.soinside.com 2019 - 2024. All rights reserved.