13

当您有如下代码时:

Bitmap bmp = new Bitmap ( 100, 100 );
Graphics g = Graphics.FromImage ( bmp );

Pen p = new Pen ( Color.FromArgb ( 128, Color.Blue ), 1 );
Brush b = new SolidBrush ( Color.FromArgb ( 128, Color.Blue ) );

g.FillEllipse ( b, 0, 0, 99, 99 );    
g.FillRegion ( b, pictureBox1.Region );

pictureBox1.BackColor = Color.Transparent;
pictureBox1.Image = bmp;

你必须丢弃笔和刷子吗?bmp和g呢?

我的主要问题是,如果这些要手动处理,为什么不在它们超出范围后立即处理?如果您不手动处理它们,会发生这种情况吗?是延迟让人们手动执行此操作吗?

4

6 回答 6

17

是的,您必须处理它们 - 不仅是钢笔和刷子,还有BitmapGraphics

它们在超出范围时不会被释放,因为变量本身是引用,而不是对象,并且 C# 编译器不知道所有权是否仍然属于这些引用(例如FillEllipse,理论上可以记住引用它已经给出,并在稍后尝试使用它 - 请记住,语言编译器没有任何特殊的库语义知识!)。

如果要指示所有权仅限于该范围,请使用以下using语句:

using (Bitmap bmp = new Bitmap ( 100, 100 ))
using (Graphics g = Graphics.FromImage ( bmp ))
using (Pen p = new Pen ( Color.FromArgb ( 128, Color.Blue ), 1 ))
using (Brush b = new SolidBrush ( Color.FromArgb ( 128, Color.Blue ) ))
{
    g.FillEllipse ( b, 0, 0, 99, 99 );    
    g.FillRegion ( b, pictureBox1.Region );
}

这将使编译器Dispose根据需要自动插入调用,确保一旦using离开相应的范围(通常是通过控制转移,如returnorbreak或异常),所有对象都被释放。

如果你有 C++ 背景,using在 C# 中直接类似于 a const std::auto_ptr,只是这里是一种语言结构,只能用于局部变量(即不能用于类字段)。

于 2009-07-30T21:50:32.797 回答
6

我知道其他人在这里放了代码示例,但我开始了,所以我会完成:

using (Bitmap bmp = new Bitmap(100, 100))
{
  using (Graphics g = Graphics.FromImage(bmp))
  {
    using (Pen p = new Pen(Color.FromArgb(128, Color.Blue), 1))
    {
      using (Brush b = new SolidBrush(Color.FromArgb(128, Color.Blue)))
      {
        g.FillEllipse(b, 0, 0, 99, 99);
        g.FillRegion(b, pictureBox1.Region);

        pictureBox1.BackColor = Color.Transparent;
        pictureBox1.Image = bmp;
      }
    }
  }
}

我总是using在我的代码中使用它,因为它会Dispose()自动调用您的对象,即使using块中引发了异常。我在SharePoint项目中经常使用它(但那是另一回事了……)。

于 2009-07-30T21:54:59.607 回答
3

一旦超出范围,C# 就不会“破坏”或处置事物。

这些类很可能会自动释放它们在其特殊Finalizer方法中持有的非托管资源,当它们在超出范围后的不确定时间被垃圾收集时将调用该方法。

但依赖它就是依赖于你无法控制的事情,并且可能暂时不会发生。

如果该类实现 IDisposable,则最佳做法是您手动调用Dispose()某处,或者最好将其包装在一个using块中。这样您就可以确定:

A. 非托管资源肯定被释放。

B. 尽快释放非托管资源。

于 2009-07-30T21:52:24.043 回答
3

如果一次性模式被正确使用,并不是绝对必要Dispose的——它会在对象完成时被调用,所以你不会泄漏资源或任何东西。

Dispose但是,一旦使用完对象就立即调用是一种很好的方式,因为一次性对象通常直接控制通常是有限的本机资源。对象通常不会立即完成/收集,因此一旦您不再使用该对象,这些资源就会闲置、浪费。处置会立即释放这些资源,以便程序的其他部分(或在某些情况下,其他程序)可以使用它们。

请注意,using当您使用完一个块时,它会自动处置该对象,这就是为什么您很少Dispose在一个using块中看到它的原因。

简短版本:如果对象实现了IDisposable,并且您的代码创建了它(即:如果它不是像 的系统对象Pens.Blue,或者Graphics您被传入OnPaint等),则应该在您完全完成它时处理它 - 无论是通过调用Dispose, 或通过调用指定调用的其他方法Dispose(Close是一个常见的方法), 或通过使用using块。您不必处理它,但您几乎总是应该处理它

于 2011-08-12T01:09:42.057 回答
1

是的,bmp、g、b 和 p 都是 IDisposable,你应该 Dispose() 所有这些。最好使用using() {}块。

有例外,当你使用 Pen p2 = Pens.Blue;你不应该处置p2。它被称为库存项目。Brushes.Black 等也是如此。

至于为什么,所有一次性类都是一样的。.Net 不使用引用计数,因此当引用超出范围时不会(不能)立即采取行动。

并将其留给垃圾收集器最终会释放它们,但它(非常)效率低下。我知道一个 ASP.NET (!) 应用程序因图形句柄不足而失败,因为没有及时处理它们。它正在生成图像。

于 2009-07-30T21:49:22.550 回答
1

Dispose 用于处理非托管资源。

因此,根据经验,我将 IDisposable 对象的任何实例都包装在 using 语句中,因此我不必担心 Pen 有哪些非托管资源。

于 2009-07-30T21:49:33.690 回答