如果您有以下代码:
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呢?
我的主要问题是,如果要手动处理这些问题,为什么他们一旦离开范围就不会被处置?如果您没有手动处理它们会发生什么?这是人们手动执行此操作的延迟吗?
答案 0 :(得分:17)
是的,您必须处理它们 - 不仅仅是笔和画笔,还有Bitmap
和Graphics
。
当它们超出范围时它们不被处理,因为变量本身是引用而不是对象,并且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
范围后处理所有对象(通常是通过{{1}等控制传输}或return
,或例外)。
如果你来自C ++背景,C#中的break
直接类似于using
,除了它是这里的语言构造,并且只能用于局部变量(即不用于类字段)。
答案 1 :(得分: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 项目使用了很多(但这是另一个故事......)。
答案 2 :(得分:3)
C#在超出范围时不会“破坏”或处置它们。
这些类最有可能自动释放他们在其特殊Finalizer
方法中保留的非托管资源,这些方法在进入后的不确定时间进行垃圾回收时将被调用超出范围。
但依靠这是依赖于你无法控制的事情,并且可能暂时不会发生。
如果该类实现了IDisposable,那么最佳做法是在某处手动调用Dispose()
,或者最好将其包装在using
块中。这样你就可以确定:
一个。非托管资源是 绝对被释放。
B中。释放非托管资源 尽快。
答案 3 :(得分:3)
如果正确使用了一次性模式,Dispose
并非严格必要 - 它将在对象完成时被调用,因此您不会泄漏资源或其他任何内容。 / p>
但是,一旦使用完对象就调用Dispose
是很好的方式,因为一次性用品通常直接控制通常有限的本地资源。对象通常不会立即被最终确定/收集,因此一旦您不再使用该对象,这些资源就会被闲置,浪费掉。处置可立即释放这些资源,因此程序的其他部分(或在某些情况下,由其他程序)可以使用它们。
注意,using
块会在您完成后自动处理该对象,这就是为什么您很少在Dispose
块中看到using
的原因。
简短版本:如果对象实现了IDisposable
,并且您的代码创建了它(即:如果它不是Pens.Blue
之类的系统对象,或者Graphics
则传入OnPaint
1}}等等,它应该在你完全完成时处理 - 无论是通过调用Dispose
,还是通过调用指定调用Dispose
的其他方法(Close
是一个常见的,或使用using
块。你不有来处置它,但你几乎总是应该。
答案 4 :(得分:1)
是的,bmp,g,b和p都是IDisposable,你应该Dispose()所有这些。最好使用using() {}
块。
有一些例外情况,当您使用Pen p2 = Pens.Blue;
时,您不应该处置p2。它被称为库存项目。对于Brushes.Black等也一样。
对于为什么,所有一次性类都是一样的。 .Net不使用引用计数,因此当引用超出范围时,不存在(不能)立即操作。
将它留给垃圾收集器最终将释放它们,但它(非常)效率低下。我知道一个ASP.NET(!)应用程序由于没有及时处理它而因图形句柄不足而失败。它正在生成图像。
答案 5 :(得分:1)
Dispose用于处理非托管资源。
因此,根据经验,我将IDisposable对象的任何实例化包装在using语句中,因此我不必担心Pen具有哪些非托管资源。