0

I have been using Unity as my IoC container for a while and I could not find the correct solution for a recurrent problem. I need to create some instances of AuditInsertLogWriter and AuditUpdateLogWriter (they implement IAuditOperationLogWriter interface) depending on the operation argument as you can see bellow:

public IAuditOperationLogWriter Create(Operation operation)
{
    switch (operation)
    {
        case Operation.Insert:
            return UnityContainer.Resolve<AuditInsertLogWriter>();
        case Operation.Update:
            return UnityContainer.Resolve<AuditUpdateLogWriter>();
        default:
            break;
    }
}

The thing is that those instances are complex to create because of their own dependencies. Moreover, I want to remove the dependency with Unity in this factory. So, my question is: how can I achieve that Unity resolves the correct type to create depending on some context?

lontivero
  • 5,235
  • 5
  • 25
  • 42
  • 1
    See here for a general answer to what is really a general type of problem: http://stackoverflow.com/questions/1943576/is-there-a-pattern-for-initializing-objects-created-via-a-di-container/1945023#1945023 – Mark Seemann Dec 22 '11 at 12:22

2 Answers2

3

If you want to remove the dependence of the factory on the container you will have to wire up all of the dependencies ahead of time.

An elegant way to do this would be with Unity's support for automatic factories.

You could define your factory like this:

public class AuditOperationLogWriterFactory
{
    private Dictionary<Operation, Func<IAuditOperationLogWriter>> auditCreator = 
        new Dictionary<Operation, Func<IAuditOperationLogWriter>>();

    public AuditOperationLogWriterFactory(Func<AuditInsertLogWriter> insert,
        Func<AuditUpdateLogWriter> update)
    {
        auditCreator[Operation.Insert] = insert;
        auditCreator[Operation.Update] = update;
    }

    public IAuditOperationLogWriter Create(Operation operation)
    {
        if (auditCreator.ContainsKey(operation))
        {
            return auditCreator[operation]();
        }

        return null;
    }
}

And then you can just resolve the factory and Unity should wire up the dependencies and the object creation is deferred until runtime (based on context). If they are complicated you may have to help via configuration (config file, code, or attributes).

IUnityContainer container = new UnityContainer();

var factory = container.Resolve<AuditOperationLogWriterFactory>();

var logWriter = factory.Create(Operation.Insert);
Randy Levy
  • 22,566
  • 4
  • 68
  • 94
  • I have taken a similar approach however what your idea looks better. I did not try this yet (I am going to do it as asap). so, I don´t know if it can work but I vote it up, thank you. – lontivero Dec 22 '11 at 05:10
  • Nice solution. I would drop the Dictionary though. For only two choices it won't buy you any performance. A simple switch or if-then-else is at least as fast. – Sebastian Weber Dec 22 '11 at 06:57
  • @SebastianWeber: I agree with your point. I [previously](http://stackoverflow.com/revisions/8599174/1) had an if-then-else but changed it. I wasn't concerned about performance here but if you do want to add a new type then you don't have to change the if or switch statement. – Randy Levy Dec 22 '11 at 14:17
0

You can register your types using registration name which could be your operation name. When resolving, use appropriate name and you'll get appropriate registration.

See overloads list of Register and Resolve methods of UnityContainer and find those with 'name' parameter. That's what you're looking for.

Sergei B.
  • 3,227
  • 19
  • 18
  • 1
    That is a valid approach but I don´t want to have a reference to the container in my factory class (It should not be there). – lontivero Dec 22 '11 at 05:15