代码之家  ›  专栏  ›  技术社区  ›  Steve Dunn supercat

当我的“idisposable”类型没有显式地被释放时,我如何判断?

  •  4
  • Steve Dunn supercat  · 技术社区  · 14 年前

    它是 hard to find 在设计/编译时,可IDisposable但未正确处理的类型。运行时有哪些方法可以找到它们?

    2 回复  |  直到 14 年前
        1
  •  7
  •   Steve Dunn supercat    14 年前

    实施是一种良好的做法 IDisposable 如果你的类型资源匮乏, 但是 这只是 良好实践 无法由编译器强制 .

    你能做的一件事就是虐待 不可分的 更值得注意的是 throw assert finalizer (请记住,如果类型被正确地处理,则终结器 不会接到电话的 因为你会打电话的 GC.SuppressFinalize 在您的处置方法中)。当应用程序完成时,以下程序在调试器的输出窗口中显示错误,原因是 Hog 未正确释放。

        class Program
        {
            static void Main(string[] args)
            {
                new Hog( ) ;
            }
        }
    
        class Hog : IDisposable
        {          
            public void Dispose( )
            {
                Dispose( true ) ;
                GC.SuppressFinalize( this ) ;
            }
    
            protected virtual void Dispose( bool disposing )
            {
                GC.SuppressFinalize( this );
            }
    
            ~Hog( )
            {
                Debug.Fail( @"You didn't dispose me!" ) ;
                Dispose( false ) ;
            }
        }
    

    您将在调试器中看到以下错误:

    ---- DEBUG ASSERTION FAILED ----
    ---- Assert Short Message ----
    You didn't dispose me!
    ---- Assert Long Message ----
        at Hog.Finalize()
    

    但是 ,如果正确使用一次性物品,例如:

    static void Main(string[] args)
    {
        using (new Hog())
            ;
    }
    

    …你什么也看不见。

    为了使事情更有用,您可以在构造函数中记录当前堆栈跟踪并将其转储到析构函数中。所以新的,更有用的 看起来像:

        class Hog : IDisposable
        {
            readonly StackTrace _stackTrace ;
    
            public Hog( )
            {
    #if DEBUG
                _stackTrace = new StackTrace();
    #endif
            }
    
            public void Dispose( )
            {
                Dispose( true ) ;
                GC.SuppressFinalize( this ) ;
            }
    
            protected virtual void Dispose( bool disposing )
            {
                GC.SuppressFinalize( this );
            }
    
            ~Hog( )
            {
    #if DEBUG
                Debug.WriteLine("FinalizableObject was not disposed" + _stackTrace.ToString());
    #endif
                Dispose( false ) ;
            }
        }
    

    在调试器输出窗口中使用它(而不处理它)可以得到:

    FinalizableObject was not disposed   at ConsoleApplication1.Hog..ctor()
       at ConsoleApplication1.Program.Main(String[] args)
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
    
        2
  •  1
  •   to StackOverflow    14 年前

    fxcop之类的代码分析工具(包含在Visual Studio的团队版本中或作为免费下载)可以检测到这一点。

    尽管偶尔会有误报/误报。