Image cache for lots of images using WeakReference on C# I'm developing an application to manage a player card-library from an online game. Each card has an image that is stored on disk with a numeric code, for example, the card with ID=1234 has his image stored as 1234.png and all the images are stored on the same folder.

As of now there are more than 3500 images for a total of 1 GB of hard disk usage.

The app doesn't need all the images loaded on memory, but depending on the context it may need from 8 to 100 images loaded on screen, and the next moment it may need a 100 different images.

As of now the images are loaded using IValueConverter and DataTemplate without storing on code behind the image, so everytime an image is needed, it is loaded from disk.

That is the current state of the project. 



Now this is the code that I want to implement:

public class ImageAccessor
{
    private string Filepath;
    private Dictionary&lt;int, WeakReference&gt; References;

    public ImageAccessor(string filepath)
    {
        Filepath = filepath;
    }

    public BitmapImage GetImage(int id)
    {
        BitmapImage image = null;
        WeakReference reference = null;

        if (!References.TryGetValue(id, out reference))
        {
            image = GetFromDisk(id);
            reference = new WeakReference(image);
            References[id] = reference;
        }
        else
        {
            image = reference.Target as BitmapImage;
            if (image == null)
            {
                image = GetFromDisk(id);
                reference.Target = image;
            }
        }

        return image;
    }

    private BitmapImage GetFromDisk(int id)
    {
        Uri uri = new Uri(Filepath + id + ".png");
        return new BitmapImage(uri);
    }
}


I don't want to implement a singleton of that class but for now let's assume that my project always uses the same instance.

Everywhere that I read about WeakReference they recommend using it for "a single large object", but what if I want to use it on "a lot of relative small-medium size objects (200~500kb each)". Except from the advice of using them for big objects, those images meet the rest of the requirements:


Having all of them all the time on memory would be very costly (1GB on RAM)
Some images may not be used for the entire life of the app
Some images may be used only one or a couple of times
Some images may be used lots of times


And by using an image I mean displaying it on a Image control 

I've never worked with weak references, and I still need to do some benchmarks to see if they are worth it, but I want to know if this code:


Is safe?
May incur on memory problems?
It can be improved?


For the sake of simplicity assume this:


The filepaths will always be correct
Every ID will correspond to an existing image always
Images will not be modified
It looks like weak reference would serve the purpose of what you are trying to achieve [IF] those images will go out of scope (not being directly referenced in any execution path) after handing them back to the caller of that method then they will be collected by GC at some point.
This MSDN article explains weak references in .net, I'll quote it here:

The garbage collector cannot collect an object in use by an application while the application's code can reach that object. The application is said to have a strong reference to the object.
A weak reference permits the garbage collector to collect the object while still allowing the application to access the object.
A weak reference is valid only during the indeterminate amount of time until the object is collected when no strong references exist. When you use a weak reference, the application can still obtain a strong reference to the object, which prevents it from being collected. However, there is always the risk that the garbage collector will get to the object first before a strong reference is reestablished.
Weak references are useful for objects that use a lot of memory, but can be recreated easily if they are reclaimed by garbage collection.

While your code should work fine, I would consider using an in-memory Cache instead with (either or both) capping the TTL (time to live) or count of objects that can occupy that cache (adding new items to the cache would invalidate and remove older items to maintain the capacity).
Check out MemoryCache class in .net framework.