Jump to content
  • Advertisement
Sign in to follow this  
slayemin

C# Indexer overloading?

This topic is 2043 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to create a class which has three dictionaries, each of which store different types of objects. I want to be able to access those dictionary items by using the dictionary key via an indexer.

/// <summary>
/// This is the asset database for all assets being used in the game.
/// </summary>
public class AssetDB
{
	Dictionary<string, Texture2D> m_textureDB;
	Dictionary<string, Model> m_modelDB;
	Dictionary<string, Effect> m_effectDB;

	public enum AssetType
	{
		Texture,
		Model,
		Effect
	}

	public AssetDB()
	{
		m_textureDB = new Dictionary<string, Texture2D>();
		m_modelDB = new Dictionary<string, Model>();
		m_effectDB = new Dictionary<string, Effect>();
	}

	public Texture2D this[string Name]      //ambiguous overload: differs only by return type!
	{
		get { return m_textureDB[Name]; }
		set { m_textureDB.Add(Name, value); }
	}

	public Model this[string Name]      //ambiguous overload: differs only by return type!
	{
		get { return m_modelDB[Name]; }
		set { m_modelDB.Add(Name, value); }
	}

	public Effect this[string Name]      //ambiguous overload: differs only by return type!
	{
		get { return m_effectDB[Name]; }
		set { m_effectDB.Add(Name, value); }
	}

	public void Clear()
	{
		m_effectDB.Clear();
		m_modelDB.Clear();
		m_textureDB.Clear();
	}
} 

Ideally, I'd like to interact with this class by doing something like this:

 

AssetDB m_db = new AssetDB();

m_db[Texture, "Grass"] = Content.Load<Texture2d>("Textures\\Grass");
m_db[Model, "Sphere"] = Content.Load<Model>("Models\\Sphere");

But, I don't know how to overload my indexer to do this correctly.

Share this post


Link to post
Share on other sites
Advertisement
The short answer is no, you can't do that. 
 
The solution would be to expose m_effectDB, m_modelDB and m_textureDB as readonly properties.
public class AssetDB
{
    private readonly Dictionary<string, Texture2D> m_textureDB = new Dictionary<string, Texture2D>();
    private readonly Dictionary<string, Model> m_modelDB = new Dictionary<string, Model>();
    private readonly Dictionary<string, Effect> m_effectDB = new Dictionary<string, Effect>();

    public IDictionary<string, Texture2D> Textures
    {
        get { return m_textureDB; }
    }

    public IDictionary<string, Model> Models
    {
        get { return m_modelDB; }
    }

    public IDictionary<string, Effect> Effects
    {
        get { return m_effectDB; }
    }
}
 
 
then use it like this
AssetDB m_db = new AssetDB();

m_db.Textures["Grass"] = Content.Load<Texture2d>("Textures\\Grass"); // mutate 
Texture grassTexture = m_db.Textures["Grass"]; // access
The potential issue with this is that your client code has access to all the methods of the Dictionary class (Clear, etc).
It's up to you as to whether that's a problem or not.

Share this post


Link to post
Share on other sites

Hmm, that works for me. The potential issue you highlight is worrisome, but considering this is a solo project, it's probably okay to ignore.

The only other alternative I can think of is to create a bunch of unweildy "GetModel(String Name)" methods, or "GetAsset(AssetType type, string Name)". It's slightly less aesthetically pleasing, but I probably shouldn't sweat over that.

Share this post


Link to post
Share on other sites

A bit late to the party, but if you want to keep the dictionary methods hidden away you could try something like the following codeproject example: Multiple Indexers in C# .

 

This allows you to expose a custom getter and setter for the list/dictionary/collection through a property name, effectively allowing something that behaves as if the language supported multiple indexers. Using the IndexProperty class in that post you could do the following with your code:

public class AssetDB
{
	Dictionary<string, Texture2D> m_textureDB;
	Dictionary<string, Model> m_modelDB;
	Dictionary<string, Effect> m_effectDB;

	public enum AssetType
	{
		Texture,
		Model,
		Effect
	}

	public AssetDB()
	{
		m_textureDB = new Dictionary<string, Texture2D>();
		m_modelDB = new Dictionary<string, Model>();
		m_effectDB = new Dictionary<string, Effect>();
		this.Texture = new IndexProperty(
			i => m_textureDB[i],
			(j,val) => m_textureDB[j]=val);
		this.Model = new IndexProperty(
			i => m_modelDB[i],
			(j,val) => m_modelDB[j]=val);
		this.Effect = new IndexProperty(
			i => m_effectDB[i],
			(j,val) => m_effectDB[j]=val);
	}

	public IndexProperty<string, Texture2D> Texture	{ get; set; }
	public IndexProperty<string, Model>     Model	{ get; set; }
	public IndexProperty<string, Effect>    Effect	{ get; set; }

	public void Clear()
	{
		m_effectDB.Clear();
		m_modelDB.Clear();
		m_textureDB.Clear();
	}
} 

You can then use the indexer properties as follows:

AssetDB m_db = new AssetDB();

m_db.Texture["Grass"] = Content.Load<Texture2d>("Textures\\Grass");
m_db.Model["Sphere"] = Content.Load<Model>("Models\\Sphere");

Share this post


Link to post
Share on other sites

Also late to the party... but...

        public class CRAZYDICTIONARY
        {
            Dictionary<Type, Dictionary<String, dynamic>> MasterDictionary;
            public CRAZYDICTIONARY()
            {
                MasterDictionary = new Dictionary<Type, Dictionary<String, Object>>();
                MasterDictionary.Add(typeof(String), new Dictionary<String, Object>());
                MasterDictionary.Add(typeof(Int32), new Dictionary<String, Object>());
                MasterDictionary.Add(typeof(DateTime), new Dictionary<String, Object>());
            }
 
            public object this[String key]
            {
                // private get { return null; }
                set
                {
                    Type t = value.GetType();
                    if (!MasterDictionary.ContainsKey(t)) throw new Exception("Value is of unsupported type");
                    if (!MasterDictionary[t].ContainsKey(key)) MasterDictionary[t].Add(key, null);
                    MasterDictionary[t][key] = value;
                }
            }
            public dynamic this[Type t, String key]
            {
                //  public set{}
                get
                {
                    if (MasterDictionary.ContainsKey(t))
                        if (MasterDictionary[t].ContainsKey(key))
                            return MasterDictionary[t][key];
                    return null;
                }
            }
 
        }

use

            CRAZYDICTIONARY cdict = new CRAZYDICTIONARY();
            cdict["ONE"] = "ABBA";
            cdict["TWO"] = 3;
            cdict["THREE"] = DateTime.Now;
            cdict["THREE"] = "THREE";
 
 
            Console.WriteLine(cdict[typeof(String), "ONE"]);
            Console.WriteLine(cdict[typeof(Int32), "TWO"]);
            Console.WriteLine(cdict[typeof(DateTime), "THREE"]);
            Console.WriteLine(cdict[typeof(String), "THREE"]);

            DateTime dt = cdict[typeof(DateTime), "THREE"];
            Console.WriteLine(dt.ToString("hh:mm:ss"));

            Console.ReadKey();

Edited by Paragon123

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!