André
André

Reputation: 343

C# Putting a class in a dictionary and creating a new instance on call

This really seems confusing but I want to create a Dictionary filled with different classes as the Values, then using letters as the keys. When I call a key in that dictionary, I need it to act as though I'm typing "new ClassInDictionary".

This is so I can create a text file with different symbols defining different blocks.

To help clear things up here's my current code:

blockIdentifier.Add("=", new BlockAir()); // Define which class corresponds to which letter
blockIdentifier.Add("-", new BlockDirt());

for (int mapX = 0; mapX < mapWidth; mapX++)
{
    for (int mapY = 0; mapY < mapHeight; mapY++)
    {
        try
        {
            Block block = blockIdentifier[mapSplit[mapY].Substring(mapX, 1)]; // Simply find which letter to use, let's pretend it's: "="
            // The line above should be creating a new instance of the class BlockAir                                                 
            block.blockX = mapX * 45; 
            block.blockY = mapY * 45;

            mapList[mapY, mapX] = block; 
        }
        catch (Exception)
        {
        }
    }
}

The variable blockIdentifier:

public static Dictionary<string, Block> blockIdentifier = new Dictionary<string, Block>();

And BlockDirt:

 public class BlockDirt : Block
{
    public int hi;

    public BlockDirt()
        : base("Dirt Block.png", 0, 0, true)
    {
    }
}

I simply need to call blockIdentifier["="] and get a new instance of the class BlockDirt(), how can I do this?

Upvotes: 1

Views: 6471

Answers (3)

Alex
Alex

Reputation: 23300

I'd say the most logical way to do it would be to have Type values in the dictionary

var blockIdentifier = new Dictionary<string, Type>();
blockIdentifier.Add("=", typeof(BlockDirt));
blockIdentifier.Add("-", typeof(BlockAir));

....

mapList[x,y] = blockIdentifier[symbol].GetConstructor(new Type[] { }).Invoke(null);

Upvotes: 0

AlanT
AlanT

Reputation: 3663

Do you want to create a new instance of the block each time or re-use a single instance of the block?

From the code it looks as if you want to create a new one each time. If so, one way is to make it a Dictionary<string, Func<Block>> where all the blocks inherit from Block (or IBlock, which might be a bit better).

note
Assumes BlockAir : IBlock and BlockDirt : IBlock

var blockLookup = new Dictionary<string, Func<IBlock>>();
blockLookup.Add("=", ()=> new BlockAir());
blockLookup.Add("-", ()=> new BlockDirt());

...

mapList[x,y] = blockLookup[symbol]();

...

or along those lines (I haven't got access to a dev. environment at the moment so apologies for any errors)

Upvotes: 8

pstrjds
pstrjds

Reputation: 17428

You could do this by storing ConstructorInfo objects in your dictionary and then create objects via reflection. Maybe kind of hacky, but I think it will work.

Here is an example using StringBuilder constructor in a dictionary (you can throw this in LINQPad to see the output).

var creator = typeof(StringBuilder).GetConstructor(new Type[]{});
var dict = new Dictionary<string, ConstructorInfo>();

dict["a"] = creator;

StringBuilder b = (StringBuilder)dict["a"].Invoke(new object[]{});
b.AppendLine("Hello World");
b.ToString().Dump();

So for your case, you want constructors for your different Block objects:

var blockIdentifier = new Dictionary<string, ConstructorInfo>();
blockIdentifier["="] = typeof(BlockAir).GetConstructor(new Type[]{});
blockIdentifier["-"] = typeof(BlockDirt).GetConstructor(new Type[]{});

Upvotes: 1

Related Questions