views:

949

answers:

2

I'm using LINQ-to-XML to query a file for a list of objects. They all have the same structure (a set number of options, a list of parameters of indeterminate length). Based on their name in the XML file, I want to use the parameters for entirely different things - so I made subclasses of this object.

My question is - how do I invoke the correct constructor dynamically, without doing something like a case statement? Or does the solution to elegantly instantiating different subclasses from XML lie elsewhere?

class Object1
{
    string name;
    OptionObj opt;
    List<Param> parameters;
}

class sonOfObject : Object1
{
    public void ExecuteSomething()
    {
         //do something with the parameters
    }
}

class secondSonOfObject : Object1
{
    public void ExecuteSomething()
    {
         //do something entirely different with the parameters
    }
}

var query = from x in xmlDoc.Descendants("Object")
    select new Object
    {
        //select the object from the XML
    }

After this bit of code I could use a copy constructor to make a sonOfObject from the more generic query object. But how do I do that dynamically, based on the name of the child class?

I know that you can get MethodInfo from a type and invoke it ala...

MethodInfo m = t.GetMethod(someName);
m.Invoke(yourObj, null);

But that would mean I would have to instantiate 9 or 10 of these child class objects (and get the type for each of them), and still ends up in some kind of case statement.

Is there a more elegant way to dynamically invoke child class constructors?

+3  A: 

Activator.CreateInstance lets you pass in a class name as a string and it will return you a new instance of that class.

David
+2  A: 

In order for a class to participate in this scheme, I'd mark it with a custom attribute, which gives it an "XML name".

Then use reflection to find all the Types marked with that attribute and put them in a Dictionary<string, Type>. At this point you need to decide how you're going to find other assemblies that might contribute types to the system. A simple approach is to look for other files with the extension .DLL in the same directory.

Then whenever you have string from the XML that you want to use to create an instance of the corresponding Type, just look the Type up in the Dictionary by name and call Type.GetConstructor and ConstructorInfo.Invoke.

The advantage of this is that the identifier in the XML is separated from the physical layout of your code - you can move types around in assemblies or rename them without invalidating old XML files.

Daniel Earwicker
+1 After re-reading the OP I believe that this really is the better solution.
Andrew Hare