如果存在垃圾回收,为什么要在使用中封装对象
本文关键字:对象 封装 为什么 存在 如果 | 更新日期: 2023-09-27 18:27:15
我在互联网上搜索了这个,但没有成功。所以希望这里有人能回答我这个问题,因为我不明白它的意义
- 这只是一个好的练习还是它真的做了一些事情
- 如果.NET有很好的垃圾收集器,我为什么要麻烦呢
示例
在这个例子中,我将使用超级简单的数据注释验证过滤器。将我的数据上下文封装在using
中有什么好处?
public static ValidationResult ValidateUniqueUsername(string username, object context)
{
using (var db = new MainDataContext()) // What's the point?
{
var user = db.Users.SingleOrDefault(x => x.Username == username);
if (user == null) return ValidationResult.Success;
return new ValidationResult("Username already taken");
}
}
using
子句基本上打开到以下内容:
ISomeDisposable disposable = new SomeDisposable();
try
{
// your code here
}
finally
{
if(disposable != null)
disposable.Dispose();
}
因此,正如您所看到的,如果您的代码抛出异常,则一次性对象将被Disposed。如果您没有抛出异常,它仍然被释放(因此使用了finally
块)。它可确保您的对象被丢弃。
using
块只是Try...Finally
块的语法糖。所以你的代码相当于这个
MainDataContext db = new MainDataContext();
try
{
var user = db.Users.SingleOrDefault(x => x.Username == username);
if (user == null) return ValidationResult.Success;
return new ValidationResult("Username already taken");
}
finally
{
if (db != null)
((IDisposable)db).Dispose();
}
这意味着,无论return
调用如何,都会调用db的Dispose
方法(因为它在finally
块中)。一般来说,处理任何实现IDisposable
的对象总是一个好主意,无论它是否被管理;尽管也有少数例外。
在托管场景中,这可能太重要,也可能不太重要,尽管我建议坚持最佳实践,但Dispose
主要用于unmanaged
资源。这些资源可能会保留下来,从而导致内存泄漏,这就是为什么在使用完它们后处理它们是个好主意。来自MSDN:
此接口的主要用途是释放非托管资源。垃圾收集器自动释放分配给当不再使用托管对象时。然而,事实并非如此可以预测垃圾回收何时发生。此外垃圾收集器不知道诸如窗口句柄或打开的文件和流。
有些对象是一次性的。这意味着它们使用不在GC范围内的外部资源(文件指针、套接字)(较低级别的资源)。
在保存这些资源的对象被销毁之前,需要先处理(释放)这些资源。如果GC在没有调用dispose方法的情况下删除了对象,那么它们可能会导致内存泄漏。
using块负责在块的末尾自动调用dispose。它类似于:
Obj obj;
try{
obj = new Obj();
//code
}
catch(Exception e){
//error
}
finally{
obj.Dispose();
}
Obj类必须实现一次性接口才能是一次性的。using块不能与非一次性对象一起使用(至少在C#中是这样)。
在使用块内使用一次性物品通常是一种很好的做法。
将数据封装在"using"中可确保对象在<using"范围之外时立即被丢弃>。
另一方面,垃圾回收器在确定对象超出范围或不再需要时处理对象。
以MSDN的方式:使用提供了一种方便的语法,可确保正确使用IDisposable对象。
正如另一个答案所说,@(Moo Juice)
"它可以确保您的对象被处理掉。"
首先阅读IDisposable模式及其用途。注意第一句话:
此接口的主要用途是释放非托管资源。
这就是重点。垃圾回收是关于实现内存而不是资源。以下是IDisposable提供帮助的地方。阅读"垃圾收集基础"中的"操作未管理的资源"一章。注意:
如果托管对象通过使用其本机文件句柄引用非托管对象,则必须显式释放非托管对象。因为垃圾收集器只跟踪托管堆上的内存。
垃圾回收是一种无法确定的机制。您可以在类中声明终结器,但不能确定何时调用它。因此,您的非托管资源可以在没有任何理由的情况下被保留。