score:1

Accepted answer

try something like this..

public enum diettype {carnivore, herbivore, omnivore};

public class factoryattribute : attribute
{
    public object something { get; protected set; }
}

[attributeusage(system.attributetargets.class)]
public class diettypeattribute : factoryattribute
{
    public diettypeattribute(diettype diettype)
    {
        this.something = diettype;
    }
}

public abstract class diet { }

[diettypeattribute(diettype.carnivore)]
public class carnivore : diet
{
}

[diettypeattribute(diettype.herbivore)]
public class herbivore : diet
{
}

abstract class abstractfactory<t> where t : class
{
    protected dictionary<enum, type> types;

    protected abstractfactory()
    {
    }

    protected void register<tenumtype, tsubtype>()
        where tenumtype: factoryattribute
    {

        types = (from assembly in appdomain.currentdomain.getassemblies()
                 from type in assembly.gettypes()
                 let attributes = type.getcustomattributes(typeof(tenumtype), true)
                 where (attributes.any()) && (typeof(tsubtype).isassignablefrom(type)) && (type.isclass)
                 select
                 new
                 {
                     dietenum = (enum)((tenumtype)attributes.first()).something,
                     diettype = type
                 }).todictionary(x => x.dietenum, x => x.diettype);
    }

    public t createinstance(enum id, params object[] param)
    {   
        return (t)activator.createinstance(types[id], param);
    }
}

class dietfactory : abstractfactory<diet>
{
    public dietfactory()
    {
        register<diettypeattribute, diet>(); 
    }
}

and testing...

void main()
{
    abstractfactory<diet> factory = new dietfactory();
    diet diet = factory.createinstance(diettype.carnivore);
    //diet is a 'carnivore'
    diet = factory.createinstance(diettype.herbivore);
    //diet is a 'herbivore'
}

edit: you don't actually need the template types for this

abstract class abstractfactory<t> where t : class
{
    protected dictionary<enum, type> types;

    protected abstractfactory()
    {
        types = (from assembly in appdomain.currentdomain.getassemblies()
                 from type in assembly.gettypes()
                 let attributes = type.getcustomattributes(typeof(factoryattribute), true)
                 where (attributes.any()) && (typeof(t).isassignablefrom(type)) && (type.isclass)
                 select
                 new
                 {
                     dietenum = (enum)((factoryattribute)attributes.first()).something,
                     diettype = type
                 }).todictionary(x => x.dietenum, x => x.diettype);
    }

    public t createinstance(enum id, params object[] param)
    {   
        return (t)activator.createinstance(types[id], param);
    }
}

and your factory is simply:

class dietfactory : abstractfactory<diet>
{
    public dietfactory()
    {
    }
}

Related Query

More Query from same tag