Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 我如何判断我的'IDisposable'类型何时未被显式处置?_.net_Garbage Collection - Fatal编程技术网

.net 我如何判断我的'IDisposable'类型何时未被显式处置?

.net 我如何判断我的'IDisposable'类型何时未被显式处置?,.net,garbage-collection,.net,Garbage Collection,它是在设计/编译时类型,可以IDisposable,但没有正确处理。运行时有哪些方法可以找到它们?如果您的类型需要资源,那么最好实现IDisposable,但是,这只是一种很好的做法,编译器无法强制执行 要使滥用IDisposable更为明显,可以做的一件事是在finalizer中使它们throw或assert(请记住,如果正确地处理了类型,则不会调用finalizer,因为您在dispose方法中调用了GC.SuppressFinalize)。以下程序在应用程序完成时在调试器的输出窗口中显示错

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

如果您的类型需要资源,那么最好实现
IDisposable
,但是,这只是一种很好的做法,编译器无法强制执行

要使滥用
IDisposable
更为明显,可以做的一件事是在
finalizer
中使它们
throw
assert
(请记住,如果正确地处理了类型,则不会调用finalizer,因为您在dispose方法中调用了
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())
        ;
}
…你什么也看不到

为了使事情更加有用,您可以在构造函数中记录当前堆栈跟踪,并将其转储到析构函数中。因此,新的、更有用的
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()

像FxCop这样的代码分析工具(包含在VisualStudio的团队版中或作为免费下载)可以检测到这一点


尽管偶尔会出现误报/误报。

您不应该访问终结器中的其他托管对象-仅发布非托管资源。在上一个示例中,finalizer~Hog正在访问托管对象_stackTrace,在finalizer运行时,该对象可能已经被收集。由于您仅在调试模式下执行此操作,因此只要不在生产环境中部署调试版本,您可能就不会受到影响。除了Dispose方法之外,如何收集它?我们知道Dispose没有被调用,因为如果它被调用,GC.SuperssFinalize将被调用,这意味着我们不在终结器中。不幸的是,这只在理论上有用。绝大多数应该实现IDisposable的类不需要终结器。使其达到99.99%@Hans-最佳实践认为您仍然应该提供一个实例,提供一个实例的良好副作用允许检查正确的处理。@Hans-这就是检查正确处理实例的全部要点。如果它被正确处置,则不会调用终结器。我提到的“最佳实践”表明您将其称为GC.SuppressFinalize。我不明白如果它不运行,费用从何而来。你能详细说明一下吗,乔?我知道“投入使用构造”的R#分析,但这只适用于本地人。