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