Sna*_*ake 29 .net c# garbage-collection dispose idisposable
请考虑以下代码:
namespace DisposeTest
{
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Calling Test");
Test();
Console.WriteLine("Call to Test done");
}
static void Test()
{
DisposeImplementation di = new DisposeImplementation();
}
}
internal class DisposeImplementation : IDisposable
{
~DisposeImplementation()
{
Console.WriteLine("~ in DisposeImplementation instance called");
}
public void Dispose()
{
Console.WriteLine("Dispose in DisposeImplementation instance called");
}
}
}
Run Code Online (Sandbox Code Playgroud)
即使我在Test();调用之后放置了一个等待循环,Dispose也永远不会被调用.所以这很糟糕.我想编写一个简单易用的类,以确保清理所有可能的资源.我不想把这个责任交给我班级的用户.
可能的解决方案:使用using或调用自己处理(基本相同).我可以强制用户使用吗?或者我可以强制调用处理吗?
呼叫GC.Collect();后Test();也不起作用.
把di以null不调用任何处置.解构器可以工作,因此对象在退出时会被解构Test()
好的,现在很清楚!
谢谢大家的答案!我会在评论中添加警告!
Dav*_*ack 48
应该提出几个要点来解决OP的问题:
using()块中.终结器: 一些开发人员将其称为析构函数.事实上,它甚至在C#4.0语言规范(第1.6.7.6节)和当前ECMA-334规范的先前版本中称为析构函数.幸运的是,第4版(2006年6月)正确定义了第8.7.9节中的终结器,并尝试在第17.12节中澄清两者之间的混淆.应该注意的是,在.NET Framework中传统上称为析构函数和析构函数/终结符之间存在重要的内部差异(不需要在这里进行详细介绍).
GC.SuppressFinalize()未调用时,.NET Framework将调用它.GC.Collect(2)第二代GC 来强制它.完成: 最终化是.NET Framework处理"优雅"清理和释放资源的方法.
虽然这肯定是您要求的更多信息,但它提供了有关工作方式以及工作原理的背景知识.有些人会争辩说他们不应该担心在.NET中管理内存和资源,但这并没有改变它需要完成的事实 - 我不认为它会在不久的将来消失.
Guf*_*ffa 21
我想编写一个简单易用的类,以确保清理所有可能的资源.我不想把这个责任交给我班级的用户.
你不能这样做.内存管理根本不是为了容纳非特定内存的资源而构建的.
IDisposable模式旨在让开发人员在完成对象时告诉对象,而不是让内存管理试图通过使用引用计数之类的东西来解决这个问题.
您可以将Finalizer用作未能正确处理对象的用户的后备,但它不能作为清理对象的主要方法.为了顺利工作,应妥善处理对象,以便不需要调用更昂贵的终结器.
Tho*_*rin 13
所有答案都(或多或少)正确,这是一个例子:
static void Test()
{
using (DisposeImplementation di = new DisposeImplementation())
{
// Do stuff with di
}
}
Run Code Online (Sandbox Code Playgroud)
手动调用Dispose也会起作用,但该using语句的优点是当您离开控制块时也会丢弃该对象,因为抛出了异常.
您可以添加一个处理资源处理的终结器,以防有人"忘记"使用IDisposable接口:
public class DisposeImplementation : IDisposable
{
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// get rid of managed resources
}
// get rid of unmanaged resources
}
~DisposeImplementation()
{
Dispose(false);
}
}
Run Code Online (Sandbox Code Playgroud)
有关其他信息,请参阅此问题.但是,这只是补偿了没有正确使用你的课程的人:)我建议你Debug.Fail()给Finalizer 添加一个很大的调用,以警告开发人员他们的错误.
如果您选择实施该模式,您将看到这GC.Collect()将触发处置.
将其用作类的模式/模板
public class MyClass : IDisposable
{
private bool disposed = false;
// 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.
private 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.
......
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
...........................
// Note disposing has been done.
disposed = true;
}
}
// 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.
~MyClass()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
Run Code Online (Sandbox Code Playgroud)
当然,正如其他人所提到的,不要忘记using(...){}阻止.