You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实例化含Bitmap自定义get的Struct时触发StackOverflow的原因与解决

解决Bitmap合并导致的StackOverflow异常(满足无中转Bitmap、无显式方法要求)

你的代码触发StackOverflow的核心原因是Display属性的getter无限递归:在Graphics.FromImage(this.Display)和return this.Display中,都在调用Display的getter,导致方法不断调用自身,直到栈空间耗尽。

我们通过缓存合并结果+自动失效机制来解决,既不用每次显式调用方法,也不会频繁创建新Bitmap浪费内存,同时保留原有属性调用的便捷性。

具体实现代码

public struct Map : IDisposable
{
    private Bitmap _background;
    private Bitmap _roomGrid;
    private Bitmap _displayCache;
    private bool _displayNeedsUpdate;

    public Bitmap Background
    {
        get => _background;
        set
        {
            _background?.Dispose();
            _background = value;
            InvalidateDisplayCache();
        }
    }

    public Bitmap Room_Grid
    {
        get => _roomGrid;
        set
        {
            _roomGrid?.Dispose();
            _roomGrid = value;
            InvalidateDisplayCache();
        }
    }

    public Bitmap Display
    {
        get
        {
            if (_displayNeedsUpdate || _displayCache == null)
            {
                // 校验依赖资源是否存在,避免空引用
                if (Background == null || Room_Grid == null)
                    return null;

                // 仅在需要时创建/重建缓存Bitmap
                _displayCache?.Dispose();
                _displayCache = new Bitmap(Background.Width, Background.Height);
                
                using (Graphics g = Graphics.FromImage(_displayCache))
                {
                    g.DrawImage(Background, new Rectangle(0, 0, Background.Width, Background.Height));
                    g.DrawImage(Room_Grid, new Rectangle(0, 0, Background.Width, Background.Height));
                }

                _displayNeedsUpdate = false;
            }

            return _displayCache;
        }
        private set { }
    }

    private void InvalidateDisplayCache()
    {
        _displayNeedsUpdate = true;
        _displayCache?.Dispose();
        _displayCache = null;
    }

    // 实现IDisposable清理Bitmap资源,避免内存泄漏
    public void Dispose()
    {
        _background?.Dispose();
        _roomGrid?.Dispose();
        _displayCache?.Dispose();
    }
}

方案说明

  • 解决递归问题:Display getter不再调用自身,而是操作私有缓存字段_displayCache,彻底终止无限递归。
  • 无中转Bitmap:仅在Background/Room_Grid变化时才重建缓存,平时复用同一个Bitmap,避免频繁创建销毁的内存开销。
  • 无需显式调用方法:每次访问Display时自动检查缓存是否有效,自动执行合并逻辑,外部调用方式和之前完全一致。
  • 资源安全:实现IDisposable接口,手动管理Bitmap资源,避免值类型持有引用资源导致的内存泄漏;同时在属性setter中及时释放旧资源。

注意事项

  • 由于struct是值类型,使用完Map实例后务必调用Dispose()方法清理资源。
  • 如果Background或Room_Grid的尺寸可能变化,当前逻辑会自动重建缓存适配新尺寸,无需额外处理。
  • 可根据实际需求添加空值校验的 fallback 逻辑(比如返回空白Bitmap而非null)。

内容的提问来源于stack exchange,提问作者Desdar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 23:55:03