C# 如果我需要另一个类中的位图,请使用 Dispose()
Posted
技术标签:
【中文标题】C# 如果我需要另一个类中的位图,请使用 Dispose()【英文标题】:C # Use Dispose() if i need Bitmap in another class 【发布时间】:2020-06-27 05:22:11 【问题描述】:我有这个类来裁剪图像:
public static Bitmap Crop(Bitmap img_crop, int w, int h, int x, int y)
Image img_crop = img_crop;
Bitmap bmp_crop = new Bitmap(w, h, PixelFormat.Format24bppRgb);
bmp_crop.SetResolution(80, 60);
Graphics gfx = Graphics.FromImage(bmp_crop);
gfx.SmoothingMode = SmoothingMode.AntiAlias;
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
gfx.DrawImage(img_cortar, new Rectangle(0, 0, w, h), x, y, w, h, GraphicsUnit.Pixel);
//bmp_crop.Save("test.bmp");
// Dispose to free up resources
img_crop.Dispose();
//bmp_crop.Dispose();// <------------ How to use this and pass Bitmap to the next class?
gfx.Dispose();
Class2(bmp_crop);
return bmp_crop;
我需要在另一个类中裁剪图像,如果我使用 Dispose() (bmp_crop.Dispose();
),在下一个类中我得到一个参数错误,我怎样才能丢弃 Bitmap 并且仍然能够在下一个中使用它上课?
public static Bitmap Class2(Bitmap bmp_crop)
...
【问题讨论】:
什么是参数错误?Class2
是代码中的方法而不是类
您不应处置 img_crop
或 bmp_crop
,因为您的 Crop()
方法也不“拥有”(img_crop
的所有权属于任何调用您的 Crop
方法(或该方法的调用者)和 bmp_crop
的 ownershop 在返回 bmp_crop
时从 Crop()
转移到其调用者。
C# 中的对象“所有权”和生命周期很容易混淆,因为 C# 没有任何语法来表示对象生命周期(例如,与 Rust 不同),这就是为什么当你有接收 IDisposable
的方法或构造函数,您记录了您的意图 w.r.t。所有权和生命周期(例如,将IDisposable
传递给构造函数以转移所有权,或者只是允许对象或方法使用它)
你不需要处理bmp_crop
,如果你把它放在多个地方也不会浪费资源。 bmp_crop
只是对位图的引用,而不是实际的位图。因此,当您将 bmp_crop
放入另一个类时,只会复制一个引用(大小为 32 位或 64 位)。实际占用资源的位图仍然是一个,您可以在完成后处理它。寻找using
声明。 ***.com/questions/212198/…
@M.kazemAkhgary bmp_crop
局部变量是对位图的唯一引用(C++ 风格的堆栈分配在这里不适用),还要注意这个方法返回 位图,所以它不能丢弃它,也不能使用using
块(除了在异常处理程序中)。
【参考方案1】:
看看您的代码实际上做了什么,它是调整大小图像,而不是裁剪它 - 所以您应该将此方法重命名为 Resize
,而不是 Crop
。
只有IDisposable
对象的“所有者”应该调用.Dispose()
或使用using
块。
“所有者”是指控制IDisposable
对象生命周期的父范围或生命周期。
这可以是一个类(如果IDisposable
被存储为一个字段),也可以是一个方法(如果IDisposable
不应该比方法或方法内的范围更有效)。
因为我假设您不打算让您的Crop
方法限制Bitmap img_crop
(源输入图像)的生命周期,您的Crop
方法不得调用bmp_crop.Dispose()
!
当一个方法创建一个新的IDisposable
对象并返回它时,该方法“拥有”该对象,直到它返回它 - 这意味着如果在方法内部抛出异常,则该方法必须处理该对象 - 这在创建对象后立即使用try/catch
完成。
在您不再需要 Graphics
对象后立即处理它是非常重要的。 System.Drawing
中的一次性类型是原生 Windows GDI 对象的包装器,它们会在您的进程中用完 GDI 句柄 - 泄漏 GDI 句柄是不好的,因为最终您会用完,然后所有图形操作都会突然停止工作(这就是为什么许多写得不好的 WinForms 程序在一段时间后开始出现图形故障)。
另外,img_crop
和bmp_crop
是变量名的糟糕选择,因为名称没有描述变量是什么,而且匈牙利表示法不好。
在下面的示例中,我将source
用于输入图像,将cropped
用于输出图像。
我会这样做:
public static Bitmap Resize( Bitmap source, int w, int h, int x, int y )
Bitmap resized = new Bitmap( w, h, PixelFormat.Format24bppRgb );
try
cropped.SetResolution(80, 60);
using( Graphics g = Graphics.FromImage( cropped ) )
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage( source, new Rectangle( 0, 0, w, h ), x, y, w, h, GraphicsUnit.Pixel );
// Pass the image to the other class/method/etc:
Class2( resized );
return resized; // Return the image to the caller, who now "owns" the image and its their responsibility to dispose of it.
catch( Exception ex )
resized.Dispose();
throw;
如果您不打算在调用Class2
方法后将cropped
返回给调用者,那么您应该删除方法中的try/catch
,而使用using
块,就像这样:
public static Bitmap Resize(Bitmap source, int w, int h, int x, int y)
using( Bitmap resized = new Bitmap( w, h, PixelFormat.Format24bppRgb ) )
cropped.SetResolution(80, 60);
using( Graphics g = Graphics.FromImage( resized ) )
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage( source, new Rectangle( 0, 0, w, h ), x, y, w, h, GraphicsUnit.Pixel );
// Pass the image to the other class/method/etc:
Class2( resized );
【讨论】:
完美,成功了。感谢上面的课程,感谢它,我设法优化了代码的其他部分。就我的另一个问题寻求帮助会不会太过分了?非常感谢您的帮助和一些未来的帮助。 ***.com/questions/62488594/…以上是关于C# 如果我需要另一个类中的位图,请使用 Dispose()的主要内容,如果未能解决你的问题,请参考以下文章