如果存在垃圾回收,为什么要在使用中封装对象

本文关键字:对象 封装 为什么 存在 如果 | 更新日期: 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提供帮助的地方。阅读"垃圾收集基础"中的"操作未管理的资源"一章。注意:

如果托管对象通过使用其本机文件句柄引用非托管对象,则必须显式释放非托管对象。因为垃圾收集器只跟踪托管堆上的内存。

垃圾回收是一种无法确定的机制。您可以在类中声明终结器,但不能确定何时调用它。因此,您的非托管资源可以在没有任何理由的情况下被保留。