C# IDisposable、终结器和非托管资源的定义
我正在努力确保我对IDisposable的理解是正确的,还有一些事情我还不太确定C# IDisposable、终结器和非托管资源的定义,c#,.net,garbage-collection,idisposable,finalizer,C#,.net,Garbage Collection,Idisposable,Finalizer,我正在努力确保我对IDisposable的理解是正确的,还有一些事情我还不太确定 IDisposable似乎有两个目的 提供按需“关闭”托管对象的约定 提供释放托管对象持有的“非托管资源”的约定 我的困惑来自于确定哪些场景中存在“非托管资源” 假设您正在使用Microsoft提供的IDisposable实现(托管)类(例如,与数据库或套接字相关) 您如何知道它是否仅为上面的1或1&2实现了IDisposable 您是否负责确保释放内部可能持有或不持有的非托管资源?您是否应该向自己调用Instan
IDisposable
似乎有两个目的
IDisposable
是的,您负责调用
Dispose
方法,或者最好使用using
语句。如果对象正在实现IDisposable
,无论发生什么情况,您都应该处置它。
using (var myObj = new Whatever())
{
// ..
}
类似于
{
var myObj;
try
{
myObj = new Whatever();
// ..
}
finally
{
if (myObj != null)
{
((IDisposable)myObj).Dispose();
}
}
} // object scope ends here
编辑:添加了try/finally,多亏了Talljoe-wow,这很难做到正确:)
EDIT2:我不是说您应该使用第二个变体。我只是想向大家展示,“使用”是一种很好的语法糖分,对于一堆可能会变得非常混乱和难以理解的代码来说。您应该始终在实现IDisposable的对象上调用Dispose(除非他们明确告诉您“这是一种有用的约定,如ASP.NET MVC的HtmlHelper.BeginForm”)。您可以使用“using”语句来简化此操作。如果将类中IDisposable的引用作为成员字段保留,则应使用实现IDisposable来清理这些成员。如果您运行像FxCop这样的静态分析工具,它会告诉您同样的情况 你不应该试图猜测接口。现在,该类可能不使用非托管资源,但下一个版本呢
instanceofmsuppliedclass.Dispose()
归根结底,对对象调用Dispose()是一种很好的做法,因为它明确地让GC知道您已使用完资源,并允许用户立即清理它,并通过让其他程序员知道此时已使用完资源来间接地记录代码。但是,即使您忘记显式地调用它,它最终也会在对象无根时发生(.Net毕竟是一个托管平台)。只有当对象具有需要隐式清理的非托管资源时(即,使用者可能忘记清理它,并且这会有问题),才应实现终结器 您对对象的内容不负责。Dispose()应该是透明的,并且释放它需要释放的内容。在那之后,你就没有责任了
非托管资源是像您将在(托管)C++中创建的资源,在这里,您通过指针和“新”语句分配内存,而不是“GCNEX”语句。当你在C++中创建一个类时,你负责删除这个内存,因为它是本地内存,或者是非托管的,垃圾回收器不关心它。您还可以通过封送分配和不安全代码来创建非托管内存
使用托管C++时,您也不必手动实现IDISPOSIGLE类。当您编写解构器时,它将被编译为Dispose()函数。
为什么它对您很重要 如果可能的话,我将一次性对象的范围包装在一个容器中。这将在使用结束时调用dispose。如果不需要,则在不再需要该对象时显式调用dispose无论是原因1还是原因2都不是必需的。如果所讨论的类是Microsoft提供的(即数据库等),那么处理Dispose(来自IDisposable)很可能已经得到了处理,这取决于您如何调用它。例如,使用数据库的标准做法如下所示:
//...
using (IDataReader dataRead = new DataReaderObject())
{
//Call database
}
这与写作基本相同:
IDataReader dataRead = null;
try
{
dataRead = new DataReaderObject()
//Call database
}
finally
{
if(dataRead != null)
{
dataRead.Dispose();
}
}
据我所知,在从IDisposable继承的对象上使用前者通常是一种良好的做法,因为它将确保适当释放资源
至于自己使用IDisposable,实现取决于您。一旦从中继承,您应该确保该方法包含处理手动创建的任何DB连接所需的代码,释放可能保留的资源或防止对象被破坏,或者只清理大型资源池(如