Abstract Factory Experiment While I should probably be using Dependency Injection via Ninject or a similar project, I have been attempting to implement an abstract factory design that would provide me with the following easy to read and use syntax:

UniversalFactory.Factory&lt;IFoo&gt;.Create&lt;FooImpl&gt;(... parameters ...);


I'm throwing this experiment on here in order to solicit some constructive feedback both with implementation logic and design reasoning.

Here is my current implementation:

public class UniversalFactory
{
    private readonly IFactory&lt;IFoo&gt; FooFactoryEx;

    public UniversalFactory()
    {
        FooFactoryEx = new FooFactory();
    }

    public IFactory&lt;T&gt; Factory&lt;T&gt;()
    {
        if (typeof (T) == typeof (IFoo))
            return (IFactory&lt;T&gt;)FooFactoryEx;
        return null;
    }
}

public interface IFactory&lt;in TF&gt;
{
    T Create&lt;T&gt;(params object[] p) where T : TF;
}

public class FooFactory : IFactory&lt;IFoo&gt;
{
    public T Create&lt;T&gt;(params object[] p) where T : IFoo
    {
        if (typeof(T) == typeof(FooImpl))
        {
            var id = Convert.ToInt32(p[0]);
            return (T)FooImpl.Create(id);
        }
        return default(T);
    }
}

public interface IFoo
{
    // Some interface
}

public class FooImpl : IFoo
{
    public int Id { get; set; }

    private FooImpl(int id)
    {
        Id = id;
    }

    public static IFoo Create(int id)
    {
        var foo =  new FooImpl(id);
        return foo;
    }
}


This code allows a UniversalFactory to be instantiated and the following to be invoked successfully:

UniversalFactory.Factory&lt;IFoo&gt;().Create&lt;FooImpl&gt;(1);


My reasoning for this approach:


All construction is easily identifiable via the call to UniversalFactory.
Factories are invoked based on the interface implementation being constructed, hiding all details about the specific factory being used from the new object request.
The object type and its construction parameters are clearly identifiable in the request.
Object construction stays in each class, and any additional updates to other objects at construction time can take place in the factory method.


My current implementation has (at a minimum) the following flaws:


There is no compile-time safety that ensures IFoo is implemented by an IFactory. Only that FooImpl implements IFoo is ensured.
UniversalFactory.Factory has to add a check for every interface supported by a factory
Individual factories have to invoke static Create() methods within each class. It would be better if the static create could be invoked in a generic way, and Create(params object[] p) somehow mapped to Create(int a, string b, ...) as needed.


Thoughts? Feedback? Is this approach unnecessary or too complex? Hopefully this experiment is, at the least, interesting to a couple of other SO folk out there.
Well what you are trying to do is not strictly speaking an abstract factory. For it to be an abstract factory the use case should look like this:

UniversalFactory.Factory&lt;IFoo&gt;  // client has no idea about IFactory&lt;IFoo&gt; implementation
                .Create(... parameters ...); // client has no idea about IFoo implementation, returns IFoo


Ideally, you should not even need to pass parameters. That is why you are building factories after all. To delegate object creation.

Other minor remarks:


where T : TF - those are not very descriptive names for generic arguments. Perhaps you can come up with better naming.
var id = Convert.ToInt32(p[0]); - i'm not sure i like Convert here. It might hide bugs and misusages. I think that strong cast is better in that case.
public static IFoo Create(int id) - i don't see any reason to use factory method.

public class FooImpl : IFoo
{
    public int Id { get; private set; }

    public FooImpl(int id)
    {
        Id = id;
    }
}


this looks a lot cleaner. Also i think Id setter should be always private.


Overall, i think unless you are doing it for studying purposes, you should just grab an existing DI library, as you've metioned yourself :)