tags:

views:

296

answers:

4

Let's say I have base class FooParent, and it has a numerous amount of FooChildren. At runtime I must create an instance of one of the FooChildren. How would I do this? I realize I could create a huge map (and use delegates) or a huge switch/case statement, but that just seems a bit sloppy. In something like PHP, I can easily create a class dynamically like this:

$className="FooClass";
$myNewFooClass=new $className; //makes a new instance of FooClass

(you can also do this using reflection).

Does .NET have anything like this? Is reflection an option, and does it have any performance penalties? If not, what other options do I have?

The type of class will be determined by a JSON request. The variable could be anything I want..it could be an integer if I wanted to do an enum, or it could be the full class name. I haven't created it yet so I'm undecided.

+5  A: 

You can do it with reflection if you really want, but there will be performance penalties. Whether they're significant or not will depend on your exact situation.

Depending on exactly what you want to do, I'd quite possibly go with either a switch/case statement or a map, as you suggest. In particular, that would be useful if you need to pass different arguments to different constructors based on the type you're constructing - doing that via reflection would be a bit of a pain in that you'd already be special-casing different types.


EDIT: Okay, so we now know that there will always be a parameterless constructor. In that case, your JSON could easily contain the class name without the namespace (if they're all in the same namespace) and your method could look something like this:

public FooParent CreateFoo(string name)
{
    if (name == null)
    {
        throw new ArgumentNullException("name");
    }
    string fullName = "Some.NameSpace." + name;
    // This is assuming that the type will be in the same assembly
    // as the call. If that's not the case, we can look at that later.
    Type type = Type.GetType(fullName);
    if (type == null)
    {
        throw new ArgumentException("No such type: " + type);
    }
    if (!typeof(FooParent).IsAssignableFrom(type))
    {
        throw new ArgumentException("Type " + type +
                                    " is not compatible with FooParent.");
    }
    return (FooParent) Activator.CreateInstance(type);
}


Where do you determine the name to use? If it's passed in somewhere, a switch statement can be very simple when reformatted away from the norm a little:

public FooParent CreateFoo(string name)
{
    switch (name)
    {
        case "Foo1":      return new Foo1();
        case "Foo2":      return new Foo2();
        case "Foo3":      return new Foo3();
        case "Foo4":      return new Foo4();
        case "FooChild1": return new FooChild1();
        default:
            throw new ArgumentException("Unknown Foo class: " + name);
    }
}

Mind you, having just written that out I'm not sure it has any real benefit (other than performance) over using Type.GetType(name) and then Activator.CreateInstance(type).

How does the caller know the class name to pass in? Will that definitely be dynamic? Is there any chance you could use generics? The more you could tell us about the situation, the more helpful we could be.

Jon Skeet
I updated my post to hopefully be a bit more clear.
ryeguy
Yes, the class will always have a paramaterless constructor.
ryeguy
+3  A: 
yourvar = Activator.CreateInstance(Type.GetType("foo.bar.Baz"));
Fernando
+3  A: 

As long as all your FooChildren have parameterless constructors, you can do this with reflection.

Activator.CreateInstance<FooChildType>();

If you don't actually have a reference to the type, and all you have is a string with the name of the class, you can do:

Activator.CreateInstance("FooChildClassName", "Fully.Qualified.AssemblyName");

There is a performance penalty with reflection, but I wouldn't get hung up about it if this turns out to be the simplest solution for you, and your performance is acceptable.

womp
A: 

If you care about performance, there is another option. Use

Type yourType = Type.GetType("FooClass");

to get the type of your class. Now you can use

ConstructorInfo ctor = yourType.GetConstructor(new Type[0]);

to get the constructor info for your constructor. If you don't want the default constructor, pass an array of the types you want to pass to the constructor. Now you can use the constructor like this:

object instanceOfFooClass = ctor.Invoke(new object[0]);

The first two steps have to be executed only once. You can save "ctor" for further use. That should be faster that calling Activator.CreateInstance.

Achim