在哪里为对象拥有的Dispose()
个对象调用IDisposable
?
public class MyClass
{
public MyClass()
{
log = new EventLog { Source = "MyLogSource", Log = "MyLog" };
FileStream stream = File.Open("MyFile.txt", FileMode.OpenOrCreate);
}
private readonly EventLog log;
private readonly FileStream stream;
// Other members, using the fields above
}
我应该为此示例实现Finalize()
吗?如果我什么都不执行怎么办?会有问题吗?
我的第一个想法是MyClass
应该实现IDisposable
。但an MSDN article中的以下陈述使我感到困惑:
仅在直接使用非托管资源时才实施IDisposable。如果您的应用只使用实现的对象 IDisposable,不提供IDisposable实现。
这个陈述是错的吗?
答案 0 :(得分:25)
如果MyClass
拥有 IDisposable
资源,则MyClass
本身应为IDisposable
,并且应该在{Dispose()
时处置封装的资源在MyClass
上调用1}}:
public class MyClass : IDisposable {
// ...
public virtual void Dispose() {
if(stream != null) {
stream.Dispose();
stream = null;
}
if(log != null) {
log.Dispose();
log = null;
}
}
}
不,你不应该在这里实现终结器。
注意:替代实现可能类似于:
private static void Dispose<T>(ref T obj) where T : class, IDisposable {
if(obj != null) {
try { obj.Dispose(); } catch {}
obj = null;
}
}
public virtual void Dispose() {
Dispose(ref stream);
Dispose(ref log);
}
答案 1 :(得分:1)
对于包含其他IDisposable
个对象it's a good and recommended practice to implement IDisposable
on your own object的对象,因此使用您的类型的其他对象可以将其包装在using
语句中:
public class MyClass : IDisposable
{
public MyClass()
{
log = new EventLog { Source = "MyLogSource", Log="MyLog" };
FileStream stream = File.Open("MyFile.txt", FileMode.OpenOrCreate);
}
private readonly EventLog log;
private readonly FileStream stream;
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free managed objects here
stream.Dispose();
}
}
// Other members, using the fields above
}
在您的情况下,您不会释放任何托管资源,因此不需要终结器。如果您 ,那么您将实现终结器并调用Dispose(false)
,向您的dispose方法指示它正在从终结器线程运行。
如果您未实施IDisposable
,则需要将其留给GC清理资源(例如,关闭Handle
上的FileStream
一旦它开始收集,你就已经开业了。假设您的MyClass
对象有资格进行收集,并且当前处于第1代。您将保持FileStream
句柄处于打开状态,直到GC运行后清理该资源。此外,Dispose
调用GC.SuppressFinalize
的许多实现都是为了避免让对象处于另一个GC周期,从初始化队列传递到F-Reachable队列。
答案 2 :(得分:1)
围绕Dispose
和Finalize
的许多建议都是由那些希望Finalize
可用作主要资源清理机制的人编写的。经验表明这种期望过于乐观。面向公众的对象获取任何类型的资源并在方法调用之间保留它们应该实现IDisposable
并且不覆盖Finalize
。如果一个对象拥有任何资源,否则如果它被放弃就不会被清除,它应该将每个这样的资源封装在一个私有对象中,然后使用Finalize
清除该对象。资源(如果需要)。
请注意,类通常不应使用Finalize
来清理其他对象持有的资源。如果Finalize
在包含对另一个对象的引用的对象上运行,则通常会应用以下几个条件之一:
Finalize
,因此该对象不需要做任何事情来清理它。Finalize
但是计划这样做,所以这个对象不需要做任何事情来清理它。Finalize
,因为所有必要的清理工作已经完成,因此该对象无需做任何事情来清理。只有在可以理解为什么上述条件都不适用的情况下,才定义Finalize
方法。虽然存在这样的情况,但它们很少见,最好不要使用Finalize
方法而不是使用不合适的方法。