0

For my game, I'm making a resource class which manager resources likes textures, sounds, fonts, etc. I made this ImageList class, which automatically loads textures during runtime as they're needed.

class TextureList
{
    private Dictionary<string, Texture> _list;

    public Texture this[string name]
    {
        get
        {
            Texture tex;
            bool success = List.TryGetValue(name, out tex);

            if (!success)
            {
                tex = Resources.LoadImage(name);
                List[name] = tex;
            }

            return tex;
        }
    }

    protected Dictionary<String, Texture> List
    {
        get
        {
            return _list ?? new Dictionary<String, Texture>();
        }
    }
}

Now I want to make to make this class generic, so that I can make a FontList or SoundList class without the hassle of changing every Texture to Sound or Font (and writing lots of duplicate code). Anyone willing to help me out on making a generic version of this?

Dlaor
  • 2,900
  • 3
  • 17
  • 14
  • 4
    Your code always create a new list (_list is never set to any value) – Julien Roncaglia Oct 26 '11 at 11:34
  • See: [Thread-safe memoization](http://stackoverflow.com/questions/1254995/thread-safe-memoization). If you don't need thread-safety, see Wes Dyer's [post](http://blogs.msdn.com/b/wesdyer/archive/2007/01/26/function-memoization.aspx) on memoization. – Ani Oct 26 '11 at 11:35
  • @VirtualBlackFox Good catch! Changing that right now. – Dlaor Oct 26 '11 at 11:44

2 Answers2

7
  1. Make your class generic
  2. In the constructor, you must pass a Func where T is your generic argument.
  3. The logic goes: When you do not find the item, the passed in Func is called and the result stored in the internal list.

so, your class becomes

var x = new Cachinglist<Texture>(s => Resources.LoadImage(s));

or

class CachingList<T>
{
    private readonly Dictionary<string, T> _list = new Blabla..();
    private readonly Func<string,T> _itemsFactory;

    public CachingList(Func<string,T> itemsFactory) {
      _itemsFactory = itemsFactory;
    }

    public T this[string name]
    {
        get
        {
            T t;

            if (!_list.TryGetValue(name, out t))
            {
                t = _itemsFactory(name);
                _list[name] = t;
            }

            return t;
        }
    }
}
flq
  • 22,247
  • 8
  • 55
  • 77
6

Assuming your textures, sounds etc all have a common base class (I'm going to call it BaseResource for this example), create a generic base class which has a loader.

public abstract class ResourceList<TYPE> where TYPE : BaseResource // change to your actual base-class or interface
{
    private Dictionary<string, TYPE> resources_ = new Dictionary<string, TYPE>();

    // loader
    protected abstract TYPE LoadImpl(string name);

    public TYPE this[string name]
    {
        get
        {
            TYPE resource;
            if(!resources_.ContainsKey(name))
            {
                resource = LoadImpl();
                resources_[name] = resource;
            }
            else
                resource = resources_[name];

            return resource;
        }
    }
} // eo class ResourceList

Now, provide concrete implementations for different resources:

public class TextureList : ResourceList<Texture>
{
    protected override Texture LoadImpl(string name)
    {
        return Resources.LoadImage(name);
    }
}

Perhaps your sound one might look like this:

public class SoundList : ResourceList<Sound>
{
    protected override Sound LoadImpl(string name)
    {
         return Resources.LoadSound(name);
    }
}
Moo-Juice
  • 38,257
  • 10
  • 78
  • 128