一切最终都是非托管资源。
不对。除了仅由框架管理(分配和释放)的 CLR 对象使用的内存之外的所有内容。
实现IDisposable
和调用Dispose
不持有任何非托管资源(直接或间接通过依赖对象)的对象是没有意义的。它不会使释放该对象具有确定性,因为您不能自己直接释放对象的 CLR 内存,因为它始终只能GC
这样做。对象是引用类型,因为值类型在方法级别直接使用时,由堆栈操作分配/释放。
现在,每个人都声称自己的答案是正确的。让我证明我的。根据文件:
Object.Finalize 方法允许对象在被垃圾回收器回收之前尝试释放资源并执行其他清理操作。
换句话说,对象的 CLR 内存在Object.Finalize()
被调用后被释放。[注意:如果需要,可以显式跳过此调用]
这是一个没有非托管资源的一次性类:
internal class Class1 : IDisposable
{
public Class1()
{
Console.WriteLine("Construct");
}
public void Dispose()
{
Console.WriteLine("Dispose");
}
~Class1()
{
Console.WriteLine("Destruct");
}
}
请注意,析构函数隐式调用Finalize
继承链中的每个Object.Finalize()
这是Main
控制台应用程序的方法:
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Class1 obj = new Class1();
obj.Dispose();
}
Console.ReadKey();
}
如果调用Dispose
是一种以确定性方式释放托管对象的方法,那么每个“Dispose”都会紧跟“Destruct”,对吗?亲眼看看会发生什么。从命令行窗口运行这个应用程序是最有趣的。
注意:有一种方法可以强制GC
收集当前应用程序域中等待完成的所有对象,但不收集单个特定对象。不过,您无需调用Dispose
即可在完成队列中拥有对象。强烈建议不要强制收集,因为它可能会损害整体应用程序性能。
编辑
有一个例外——状态管理。Dispose
如果您的对象碰巧管理外部状态,则可以处理状态更改。即使状态不是非托管对象,由于特殊处理,使用它也非常方便IDisposable
。示例是安全上下文或模拟上下文。
using (WindowsImpersonationContext context = SomeUserIdentity.Impersonate()))
{
// do something as SomeUser
}
// back to your user
这不是最好的例子,因为在WindowsImpersonationContext
内部使用系统句柄,但你得到了图片。
底线是,在实施时,IDisposable
您需要(或计划)在Dispose
方法中做一些有意义的事情。否则只是浪费时间。IDisposable
不会改变 GC 管理对象的方式。