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_cropbmp_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_cropbmp_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()的主要内容,如果未能解决你的问题,请参考以下文章

如何在c#中访问内部类中的外部类的变量[重复]

加速位图灰度转换,OpenMP 是 C# 中的一个选项吗?

C#:基类中的受保护方法;无法使用来自另一个类的派生类对象进行访问[重复]

如何使静态类中的所有方法在c#中的另一个静态类中可用

在 C# 中打印和打印预览位图

从另一个类中的另一个线程创建和显示 WindowsForm - C# [关闭]