Other answers show that you need to use the factory pattern, but I would like to give you a more βpracticalβ example of how you do this. I did exactly what you did, however I worked with the EPL2 printer language . When I saw X , I needed to create an instance of the Rectangle class, when I saw A I needed to create an instance of the Text class.
(I wrote this a long time ago , so I'm sure some of my things can be improved).
public partial class Epl2CommandFactory { #region Singelton pattern private static volatile Epl2CommandFactory m_instance; private static object m_syncRoot = new object(); public static Epl2CommandFactory Instance { get { if (m_instance == null) { lock (m_syncRoot) { if (m_instance == null) { m_instance = new Epl2CommandFactory(); } } } return m_instance; } } #endregion #region Constructor private Epl2CommandFactory() { m_generalCommands = new Dictionary<string, Type>(); Initialize(); } #endregion #region Variables private Dictionary<string, Type> m_generalCommands; private Assembly m_asm; #endregion #region Helpers private void Initialize() { Assembly asm = Assembly.GetAssembly(GetType()); Type[] allTypes = asm.GetTypes(); foreach (Type type in allTypes) { // Only scan classes that are not abstract if (type.IsClass && !type.IsAbstract) { // If a class implements the IEpl2FactoryProduct interface, // which allows retrieval of the product class key... Type iEpl2FactoryProduct = type.GetInterface("IEpl2GeneralFactoryProduct"); if (iEpl2FactoryProduct != null) { // Create a temporary instance of that class... object inst = asm.CreateInstance(type.FullName); if (inst != null) { // And generate the product classes key IEpl2GeneralFactoryProduct keyDesc = (IEpl2GeneralFactoryProduct)inst; string key = keyDesc.GetFactoryKey(); m_generalCommands.Add(key, type); inst = null; } } } } m_asm = asm; } #endregion #region Methods public IEpl2Command CreateEpl2Command(string command) { if (command == null) throw new NullReferenceException("Invalid command supplied, must be " + "non-null."); Type type; if (!m_generalCommands.TryGetValue(command.Substring(0, 2), out type)) m_generalCommands.TryGetValue(command.Substring(0, 1), out type); if (type != default(Type)) { object inst = m_asm.CreateInstance(type.FullName, true, BindingFlags.CreateInstance, null, null, null, null); if (inst == null) throw new NullReferenceException("Null product instance. " + "Unable to create necessary product class."); IEpl2Command prod = (IEpl2Command)inst; prod.CommandString = command; return prod; } else { return null; } } #endregion }
How the code works, I use a singleton pattern to create a factory class so that people can call var command = Epl2CommandFactory.Instance.CreateEpl2Command("...") ; passing in command line EPL2 and returning an instance of the class representing this particular class.
During initialization, I use reflection to search for classes that support the IEpl2GeneralFactoryProduct interface, if the class supports the interface, the factory stores one or two letter codes representing the printer command in the type dictionary.
When trying to create a command, the factory looks at the printer command in the dictionary and creates the correct class, and then passes the full command line to this class for further processing.
Here is a copy of the command class, and these are the parents if you want to see it
Rectangle :
[XmlInclude(typeof(Rectangle))] public abstract partial class Epl2CommandBase { }
DrawableItemBase :
public abstract class DrawableItemBase : Epl2CommandBase, IDrawableCommand { protected DrawableItemBase() { Location = new Point(); } protected DrawableItemBase(Point location) { Location = location; } protected DrawableItemBase(int x, int y) { Location = new Point(); X = x; Y = y; } private Point _Location; [XmlIgnore] public virtual Point Location { get { return _Location; } set { _Location = value; } } [XmlIgnore] public int X { get { return _Location.X; } set { _Location.X = value; } } [XmlIgnore] public int Y { get { return _Location.Y; } set { _Location.Y = value; } } abstract public void Paint(Graphics g, Image buffer); }
Epl2CommandBase :
public abstract partial class Epl2CommandBase : IEpl2Command { protected Epl2CommandBase() { } public virtual byte[] GenerateByteCommand() { return Encoding.ASCII.GetBytes(CommandString + '\n'); } public abstract string CommandString { get; set; } }
Different interfaces:
public interface IEpl2GeneralFactoryProduct { string GetFactoryKey(); } public interface IEpl2Command { string CommandString { get; set; } } public interface IDrawableCommand : IEpl2Command { void Paint(System.Drawing.Graphics g, System.Drawing.Image buffer); }