C# 从终结器调用托管资源是否安全?(如果我选择null)
拨打以下电话是否不安全: component.Dispose();(如果我选择null) 如果我将代码更改为以下内容,则从终结器:C# 从终结器调用托管资源是否安全?(如果我选择null),c#,dispose,finalizer,C#,Dispose,Finalizer,拨打以下电话是否不安全: component.Dispose();(如果我选择null) 如果我将代码更改为以下内容,则从终结器: ~MyResource() { Dispose(); } public void Dispose() { // Check to see if Dispose has already been called. if(!this.disposed) { if(component != null) com
~MyResource()
{
Dispose();
}
public void Dispose()
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
if(component != null) component.Dispose(); // !!! //
CloseHandle(handle);
handle = IntPtr.Zero;
disposed = true;
}
GC.SuppressFinalize(this);
}
我知道这是可行的,但安全吗
(来自下面的例子?)
代码示例:(更改代码之前)
如果不知道“组件”的实现细节,很难确定这样做是否安全。对象的终结是无序的,不考虑包含层次结构,因此,尽管“组件”实例可能不是
null
,但在您对其调用Dispose
时,它可能已经终结。通常,编写Dispose
方法时没有考虑到这种安全性,因为它们只希望在对象最终确定之前被调用
在你甚至想考虑做一些聪明的事情,比如在终结器中触摸其他物体时,读关于这个主题的文章。p>
通常,除了在非常特殊的情况下,您知道所包含对象的
Dispose
方法的行为与预期的一样,即使在它被最终确定时被调用,我假设您所询问的模式不安全,并且将坚持推荐的模式,即传递bool disposing
参数,并且仅接触托管对象(如果为true
),在.net中,通过任何方式访问的任何对象都保证存在,可以访问此类对象的字段,并且可以调度对该对象的属性访问或方法调用,就像在任何其他情况下一样。唯一不能保证的是系统是否已经在引用的对象上运行了Finalize
方法。由于系统已经在一个对象上运行了Finalize
,所以以前可以做一些有用的事情的方法将不再能够这样做,但这是对象的Finalize()的一个函数
例行程序,与垃圾收集器本身无关。+1从未见过任何人对代码的评论如此之好。+1可能重复@Niklas,请阅读,一切都解释得很清楚。@ken2k-感谢您的阅读,但这不是我直接问题的答案!谢谢,如果我只使用内置类型的托管资源,比如datacontext。那么我想它不需要终结器,只要dispose()方法就足够了!(为了防止datacontex使用其终结器),您可能希望查看和/或搜索此网站和其他地方的术语“freachable”。
using System;
using System.ComponentModel;
// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.
public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
public static void Main()
{
// Insert code here to create
// and use the MyResource object.
}
}