views:

82

answers:

2

I have a abstract base class that I have many inherited classes coming off of. What I would like to do is a static member takes in a string, the first class that can parse the string (only one of the inherited classes should be able to) and return a instance of the inherited class.

This is what i am currently doing.

public static Epl2Command GenerateCommandFromText(string command)
{
    lock (GenerateCommandFromTextSyncRoot)
    {
        if (!Init)
        {
            Assembly a = Assembly.GetAssembly(typeof(Epl2Command));
            Types = new List<Type>(a.GetTypes());
            Types = Types.FindAll(b => b.IsSubclassOf(typeof(Epl2Command)));
            Init = true;
        }
    }
    Epl2Command ret = null;
    foreach (Type t in Types)
    {

        MethodInfo method = t.GetMethod("GenerateCommand", BindingFlags.Static | BindingFlags.Public);

        if (method != null)
            ret = (Epl2Command)method.Invoke(null, new object[] { command });
        if (ret != null)
            break;
    }
    return ret;
}

I would like it so my code would check all inherited classes without having future programmers come back and edit this function when they add more inherited classes.

Is there a way I can force a inherited class to implement their own GenerateCommand(string)?

public static abstract Epl2Command GenerateCommand(string command) is not valid c#. Or am I hammering a nail in with a shoe when I should be using a hammer; any better way of doing this class factory would be appreciated.

A: 

What you are eluding to is the Factory Method:

http://www.dofactory.com/Patterns/PatternFactory.aspx

Here is a link how to implement it.

Kevin
Using that pattern requires a different class to be called for each different type of sub-class. I would prefer if I could do it with one factory and it would be smart enough to find all who inherit it and spit out the correct type without editing Epl2Command every time a class is added.
Scott Chamberlain
+1  A: 

C# does not support static interfaces, so you can't define a static builder method like

public interface ICommand
{
    static ICommand CreateCommand(string command);
}

I agree with Kevin that you need a Factory pattern. I'll go a step further and say that you need a builder per command type, too. Like this

public interface ICommandBuilder
{
    bool CanParse(string input);
    ICommand Build(string input);
}

public interface ICommandBuilder<TCommand> : ICommandBuilder 
    where TCommand : ICommand
{
    TCommand Build(string input);
}

Then your factory can accept any input command string, query all builders if they can parse that string, and run Build on the one that can.

public interface ICommandFactory
{
    ICommand Build(string input);
}

public class CommandFactory
{
    public ICommand Build(string input)
    {
        var builder = container.ResolveAll(typeof(ICommandBuilder))
            .First(x => x.CanParse(input));
        return builder.Build(input);
    }
}
Anthony Mastrean
Great article by Jon Skeet on static interfaces. http://goo.gl/WPpV
Anthony Mastrean
where did contrainer come from?
Scott Chamberlain
It's pseduo-code, assuming you're using an inversion of control container... Windsor, StructureMap, etc. If you aren't using an IoC, you'll have to find all ICommandBuilder types and instantiate them manually.
Anthony Mastrean