首页 > 解决方案 > C# 如果我需要另一个类中的位图,请使用 Dispose()

问题描述

我有这个类来裁剪图像:

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)
    {
    ...
    }

标签: c#classbitmapcropdispose

解决方案


  • 查看您的代码实际执行的操作,它正在调整图像大小,而不是裁剪它 - 所以您应该将此方法重命名为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_cropandbmp_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;
    }
}

如果您打算cropped在调用您的方法后返回给调用者,Class2那么您应该删除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 );
    }
}

推荐阅读