Use a Dictionary for creating new instances of objects

I wonder if it is possible to use Dictionary<string, MyType> as a object factory, in other words, given a string "Foo" I want to retrieve a new instance of my Foo class.

private Dictionary<string, MyType> ClassDic = new Dictionary<string, MyType>()
{
     {"Foo", new Foo()},
     {"Bar", new Bar()},
     //many more

}

What I basically want to do is to replace a lot of if statements and then creating manually the object:

 if(line == "Foo") { Stuff.Add(new Foo() { ID = i }; }
 if(line == "Bar") { Stuff.Add(new Bar() { ID = i }; }

(Foo and Bar derive both from the same base class)

to something like this:

BaseClass myObject;
if(ClassDic.TryGetValue(line, out myObject))
{
     Stuff.Add(myObject);
     myObject.ID = i;
}

The problem is in my code the dictionary gives me the same reference of an object, so the properties overwrite (for example if I have 300 objects, all 300 will have the same ID (the last one) in the end).

I am also open to other approaches to this problem.

Jon Skeet
people
quotationmark

I wonder if it is possible to use Dictionary as a object factory, in other words, given a string "Foo" I want to retrieve a new instance of my Foo class.

Given then that you want to create a new instance, I would suggest using a Dictionary<string, Func<MyType>> like this:

private static readonly Dictionary<string, Func<MyType>> Factories =
    new Dictionary<string, Func<MyType>>()
{
     {"Foo", () => new Foo() },
     {"Bar", () => new Bar() },
}

Then you can use:

MyType x = Factories[name]();

Having said that, if the key is really just the name of the class, you can use reflection:

Type type = Type.GetType(name);
MyType x = (MyType) Activator.CreateInstance(type);

Note that name here has to be the namespace-qualified class name, so you may need to prepend the namespace to the name that you pass. It will also only look for the type in the currently executing assembly and mscorlib; if you need types from other assemblies, you can either pass in the assembly-qualified name, or call Assembly.GetType(name) instead on the relevant assembly.

people

See more on this question at Stackoverflow