C# 通过ResourceManager获取图像GetObject—;每次调用它或存储结果?

C# 通过ResourceManager获取图像GetObject—;每次调用它或存储结果?,c#,resourcemanager,C#,Resourcemanager,假设我必须在某个控件上显示一些图形。但根据某些条件,将有三个图像切换。在资源文件中添加了三个位图 因此,我通过调用ResourceManager.GetObject来检索它们 问题是,如果是: 每次我必须切换图像时,我都会调用GetObject来获取它并分配给控件 或 在开始时为每个图像保留GetObject的结果,这样对GetObject只有3次调用。从我的变量中指定图像 使用CLR探查器查看时,执行1)似乎会产生很多GC句柄。 希望知道2)的任何不良副作用 非常感谢。每次调用GetObjec

假设我必须在某个控件上显示一些图形。但根据某些条件,将有三个图像切换。在资源文件中添加了三个位图

因此,我通过调用ResourceManager.GetObject来检索它们

问题是,如果是:

  • 每次我必须切换图像时,我都会调用GetObject来获取它并分配给控件 或
  • 在开始时为每个图像保留GetObject的结果,这样对GetObject只有3次调用。从我的变量中指定图像
  • 使用CLR探查器查看时,执行1)似乎会产生很多GC句柄。 希望知道2)的任何不良副作用


    非常感谢。

    每次调用
    GetObject
    都将从程序集中读取图像,并将其加载到
    位图
    对象中


    多次调用会产生大量开销;您应该存储图像。

    状态是ResourceManager.GetObject返回资源的值。由于听起来各个位图在运行时不会改变,因此我看到的唯一不好的一面是#2的内存占用会更大。

    关于每次需要使用资源中的图像时调用“ResourceManager.GetObject”,需要指出的另一点是,每次调用“ResourceManager.GetObject”时,似乎都会创建一个新的Windows句柄。对你来说可能没什么大不了的,但如果你像我们一样坚持一段时间,可能会引起问题

    我们有一个DataGridView,我们将图像从资源推送到网格的不同字段,当网格超过3000行时,我们实际上超过了32位程序允许的最大Windows句柄

    错误出现在随机参数异常中,消息为“参数无效”。我们花了几个小时考虑内存泄漏,但最终找到了我们用网格加载的GUI。应用程序处理从700-1000到超过10K,甚至在加载完成之前,整个程序都会崩溃,无法恢复。因此,我在此推荐选项2。

    我也在我的类中实现了

    举个例子,下面是我的代码摘录:

    internal static class MyResourcesHolder
    {
        private static Image _i1;
        private static Image _i2;
        private static Image _i3;
        private static Image _i4;
        private static Image _i5;
    
        public static Image MyImage01 => _i1 ?? (_i1 = Resources.MyImage01);
        public static Image MyImage02 => _i2 ?? (_i2 = Resources.MyImage02);
        public static Image MyImage03 => _i3 ?? (_i3 = Resources.MyImage03);
        public static Image MyImage04 => _i4 ?? (_i4 = Resources.MyImage04);
        public static Image MyImage05 => _i5 ?? (_i5 = Resources.MyImage05);
    }
    

    也许有一天这会对某些人有所帮助。

    我有一个WinForms应用程序,它使用许多相同表单的实例,每个实例都有许多用于菜单和按钮等的图像和图标。所有这些图像都存储在自动生成的
    [ProjectName].Properties.Resources
    类中

    我注意到内存使用率非常高;在仅仅10个左右的表单实例之后,它就使用了数百MB的内存,并且在多个实例之后可以轻松地跨越1+GB。我将问题追溯到
    ResourceManager.GetObject
    方法。
    GetObject
    方法返回请求的每个对象的一个新实例,这在我看来似乎是错误的

    与其让所有这些图像实例占用内存而不在范围内,为什么不在将来的表单实例中重用它们呢?因此,我创建了一个自定义的
    CachedResourceMananger
    类,并重写
    GetObject
    方法以返回请求对象的缓存实例

     /// <summary>
    /// A custom Resource Manager that provides cached instances of objects.
    /// This differs from the stock ResourceManager class which always
    /// deserializes and creates new instances of every object.
    /// After the first time an object is requested, it will be cached
    /// for all future requests.
    /// </summary>
    public class CachedResourceManager : System.Resources.ResourceManager
    {
        /// <summary>
        /// A hashtable is used to store the objects.
        /// </summary>
        private Hashtable objectCache = new Hashtable();
    
        public CachedResourceManager(Type resourceSource) : base(resourceSource)
        {
        }
    
        public CachedResourceManager(string baseName, Assembly assembly) : base(baseName, assembly)
        {
        }
    
        public CachedResourceManager(string baseName, Assembly assembly, Type usingResourceSet) : base(baseName, assembly, usingResourceSet)
        {
        }
    
        public CachedResourceManager() : base()
        {
        }
    
        /// <summary>
        /// Returns a cached instance of the specified resource.
        /// </summary>
        public override object GetObject(string name)
        {
            return GetObject(name, null);
        }
    
        /// <summary>
        /// Returns a cached instance of the specified resource.
        /// </summary>
        public override object GetObject(string name, CultureInfo culture)
        {
            // Try to get the specified object from the cache.
            var obj = objectCache[name];
    
            // If the object has not been cached, add it
            // and return a cached instance.
            if (obj == null)
            {
                objectCache[name] = base.GetObject(name, culture);
                obj = objectCache[name];
            }
    
            return obj;
        }
    }
    
    这大大减少了内存使用,也大大缩短了新表单实例的加载时间

    internal class Resources
    {
        private static CachedResourceManager resourceMan;
    
        private static global::System.Globalization.CultureInfo resourceCulture;
    
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal Resources() {
        }
    
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static CachedResourceManager ResourceManager 
        {
            get {
                   if (object.ReferenceEquals(resourceMan, null))
                   {
                      CachedResourceManager temp = new CachedResourceManager("Project.Properties.Resources", typeof(Resources).Assembly);
                      resourceMan = temp;
                   }
                   return resourceMan;
                }
        }
    
        // Image/object properties for your resources
    
    } // End of resources class