通过ResourceManager GetObject获取图像 - 每次调用它还是存储结果?

lex*_*ton 6 c# resourcemanager

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

所以,我通过调用ResourceManager.GetObject来检索它们.

问题是,它应该是:

  1. 每次我必须切换图像,我调用GetObject来获取它并分配给控件或
  2. 在开始时为每个图像保存GetObject的结果,这样就只能对GetObject进行3次调用.从我的变量中分配图像.

使用CLR Profiler查看时,执行1)似乎会产生大量GC句柄.希望知道2)的任何不良副作用.

非常感谢.

SLa*_*aks 7

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

多次调用会产生很大的开销; 你应该存储图像.


Bob*_*y L 5

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

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

与其让所有这些图像实例吸收内存而超出范围,为什么不将它们重新用于将来的 Form 实例呢?因此,我创建了一个自定义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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我修改了自动生成的[ProjectName].Properties.Resources类中的资源管理器属性和字段以使用自定义资源管理器,global::System.Resources.ResourceManager并将CachedResourceManager.

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
Run Code Online (Sandbox Code Playgroud)

这极大地减少了内存使用量,并大大缩短了新 Form 实例的加载时间。