Normally IoC should never go into the code below the level of module/component registration. That’s the rule.
But what if some specific component needs to resolve components based on some conditions (i.e. resolving by name when name is passed externally)?
You can use dictionary if the components are singletons, but this would not work if they have to be resolved in the current scope. For example, we might need to execute some workflow class knowing only its name and interface. And some workflow class (neither we know, nor do we care) could just need to access the data store within the scope of the current session.
These simple interface declarations help me to manage scenarios like this with a couple of lines of code, while keeping the IoC intrusion minimal:
public interface IResolver<Param, Object>
{
Object Resolve(Param param);
}
public interface IResolver<Object> : IResolver<string, Object> { }
Additionally there is a simple class to lend IoC to the components with inlining:
public class Resolver<Param, Object> : IResolver<Param, Object>
{
private readonly Func<Param, Object> _function;
public Resolver(Func<Param, Object> function)
{
_function = function;
}
public Object Resolve(Param param)
{
return _function(param);
}
}
public sealed class Resolver<Object> :
Resolver<string, Object>, IResolver<Object>
{
public Resolver(Func<string, Object> function) : base(function)
{
}
}
With that you can register named resolution of some interface (ICommand, for example) with this nice statement:
builder.Register(scope => new Resolver<ICommand>(
name => scope.ResolveByName<ICommand>(name)))
.As<IResolver<ICommand>>()
.WithScope(InstanceScope.Container);
and then it could be later used in any component like
public sealed class TaskExecutor
{
private readonly Resolver<ICommand> _commands;
public TaskExecutor(Resolver<ICommand> commands)
{
_commands = commands;
}
...
_commands.Resolve(commandName).Execute();
...
}
Remarks:
- The resolution interfaces should always be explicitly written. That’s just to keep the code under control.
- This function-based resolver interface simplifies unit testing quite a bit (especially if you use MockContainer).
- Do not try this code at home with your IoC container unless this container is Autofac.
- Using some global static class (i.e.: IoC.ResolveByName…) is not a valid solution either, because:
- That’s global static class and its usage just complicates code management and testing
- Static resolution would not have any clue about the current scope (rendering it useless)

3 Responses to “How to avoid tight IoC coupling in non-deterministic resolution scenarios?”