如果我理解正确,.net运行时将始终为我清理垃圾。因此,如果我创建新对象并在代码中停止引用它们,运行时将清理这些对象并释放它们占用的内存。
既然如此,为什么有些对象需要有析构函数或dispose方法呢?当它们不再被引用时,运行时不会自动清理吗?
如果我理解正确,.net运行时将始终为我清理垃圾。因此,如果我创建新对象并在代码中停止引用它们,运行时将清理这些对象并释放它们占用的内存。
既然如此,为什么有些对象需要有析构函数或dispose方法呢?当它们不再被引用时,运行时不会自动清理吗?
public void Log(string line)
{
var sw = new StreamWriter(File.Open(
"LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None));
sw.WriteLine(line);
// Since we don't close the stream the FileStream finalizer will do that for
// us but we don't know when that will be and until then the file is locked.
}
StreamWriter
对象的终结器。这会带来问题,因为在此期间,可能会再次调用该方法来写日志,但这次将失败,因为文件仍然被锁定。public void Log(string line)
{
using (var sw = new StreamWriter(File.Open(
"LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))) {
sw.WriteLine(line);
}
// Since we use the using block (which conveniently calls Dispose() for us)
// the file well be closed at this point.
}
顺便说一句,技术上来说,finalizers 和 destructors 意思相同;我更倾向于称 C# 的析构函数为 "finalizers",因为否则它们很容易与 C++ 的析构函数混淆,而 C++ 的析构函数与 C# 不同,是确定性的。
using
有其优点和缺点,但我不确定前者是否超过后者。当然,这取决于应用程序,但在我编写的几乎每个程序中,非托管资源管理都是至关重要的一部分,而C++在这方面让我的生活更加轻松。 - Konrad RudolphIDisposable
字段,该字段是通过构造函数而不是字段初始化程序初始化的? 可以通过将IDisposable
类型封装在struct DisposableHolder<T>:IDisposable where T:class
类型中来实现它,但那似乎很棘手。 - supercat有些对象可能需要清理低级别的项目。例如需要关闭的硬件等。
.NET垃圾回收器知道如何处理.NET运行时中的托管对象。但Dispose模式(IDisposable)主要用于应用程序正在使用的非托管对象。
换句话说,.NET运行时不一定知道如何处理所有类型的设备或句柄(关闭网络连接、文件句柄、图形设备等),因此使用IDisposable提供了一种方式来表明“让我实现自己的清理”在一个类型中。看到这个实现,垃圾回收器可以调用Dispose()并确保管理堆之外的事物被清理。