如何判断我的`IDisposable`类型没有明确处理?

Ste*_*unn 4 .net garbage-collection

这是很难找到在设计/编译是那些没有正确地放置了IDisposable,但时间类型.在运行时有哪些方法可以找到它们?

Ste*_*unn 7

IDisposable如果您的类型是资源饥饿,那么实现是一种很好的做法,但是,这只是一种很好的做法,并且不能由编译器强制执行.

有一两件事你可以做,使滥用IDisposableS比显着,是让他们throwassertfinalizer(记住,如果你的类型妥善处理,终结不会被调用,因为你已经叫GC.SuppressFinalize你的Dispose方法).以下程序在应用程序完成时显示调试器输出窗口中的错误,因为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 ) ;
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

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

但是,如果您确实正确使用了一次性物体,例如:

static void Main(string[] args)
{
    using (new Hog())
        ;
}
Run Code Online (Sandbox Code Playgroud)

......你什么都看不到.

为了使事情更有用,您可以在构造函数中记录当前堆栈跟踪并将其转储到析构函数中.所以新的,更有用的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 ) ;
        }
    }
Run Code Online (Sandbox Code Playgroud)

并使用它(不处理它)会在调试器输出窗口中给你这个:

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()
Run Code Online (Sandbox Code Playgroud)

  • @Hans - 这是检查正确处理实例的重点.如果它被正确处理,则不会调用终结器.我提到的"最佳实践"声明您调用GC.SuppressFinalize.如果它从未运行,我不明白费用来自哪里. (2认同)