Humblecoder

Caution, this blog may be ironically named

Detangling Service Locator From Dependency Injection

| Comments

I’m sure like many exploring Dependency Injection (DI) for the first time the biggest problem I had, was how to rid the world of those pesky little new statements.  The first application I tried to use DI with in anger was DirLinker.  I had no prior knowledge of any of the DI frameworks and started looking at patterns that would help me remove all the new statements.  Unfortunately, I hit up on service locator and the rest is a mess history.  I ended up with code the looks like the following inside DirLinker:

IFile aFile = ClassFactory.CreateInstance<IFile>();
aFile.SetFile(file);

There is a couple of things that bother me about this.  First is the static, I’m not a fan of statics at all, infact, I hate them.  Next is the SetFile call, for any meaningful work to be done with this class you need to pass in a filename and it should be a constructor argument.  In all fairness the SetFile problem is more to do with the limitations of my roll your own DI framework than anything else.

In spite of my niggling doubts, it worked so I left it alone.  Fast forward to last week when I came across a blog post entitled Service Locator is an Anti- Pattern. This confirmed my initial discomfort and highlighted a problem I hadn’t thought of, namely that the class doesn’t advertise its dependencies.  Very bad for reuse.

Factories

As the blog post suggests a better way of doing this would have been to use factories so lets go over a couple of examples on how this could be achieved.

Virtual Instance Methods

This is a method I would use when trying to a create a seam in legacy code to inject a dependency for unit testing.  To do this you create a virtual method on the class that needs to create the object. In the unit test inherit from the class under test and override the factory method to return your mock or stub.  For example:

public class FileConsumer
{
    protected virtual IFile GetFile(String filename)
    {
        return new FileImp(filename);
    }  
    public void DoSomething()
    {
        IFile fileA = GetFile("test.txt");
        IFile fileB = GetFile("test2.txt");
        //uses files
    }
}  
[TestFixture]
public class FileConsumerTests : FileConsumer
{
    protected override IFile GetFile(string filename)
    {
        return new FileMock(filename);
    }  
    [Test]
    public void DosomethingTest()
    {
        //Code to perform test
    }
}

This is good because it’s clear to any maintainer what the dependency is and where it is coming from.

Abstraction Factory Pattern

This would loudly and proudly advertise the dependency on the ability to create IFile objects.  It works by creating a class with methods solely responsible for creating IFile objects and then taking this as dependency for your class.  For example:

public interface IFileFactory
{
    IFile CreateFile(String filename);
}  
public class FileFactory : IFileFactory
{
    public IFile CreateFile(string filename)
    {
        return new FileImp(filename);
    }
}  
public class FileConsumer
{
    IFileFactory _fileFactory;  
    public FileConsumer(IFileFactory fileFactory)
    {  
        _fileFactory = fileFactory;
    }  
    public void DoSomething()
    {
        IFile fileA = _fileFactory.CreateFile("test.txt");
        IFile fileB = _fileFactory.CreateFile("test.txt");
        //uses files
    }
}

This is the pattern recommended by the blog post and it covers all the things I don’t like about Service Locator.  But I think we could take advantage of some of C#’s language features and the fact we are creating objects via a container to achieve something similar but with less code.

Delegate Factories

Before I go into this a little disclaimer, this is totally and utterly inspired by Autofac’s wonderful generated delegate factory functionality, you can read more about it here.

OK, honesty out of way lets look at what the container knows and what it does. The DI container knows what Interfaces should map on to what concrete types and it has the ability to resolve constructor arguments for types that it knows about.  This is just a generic version of a factory so it makes sense to take advantage of it.

One way would be to use Func() (and its friends).  If the class being constructed requires a constructor parameter of Func where TResult is the required interface, the container could generate an appropriate delegate at runtime and pass it in.  For example:

   public class FileConsumer
   {
       Func<IFile> _fileFactory;  
       public FileConsumer(Func<IFile> fileFactory)
       {  
           _fileFactory = fileFactory;
       }  
       public void DoSomething()
       {
           IFile fileA = _fileFactory();
           IFile fileB = _fileFactory();  
           //uses fileA
       }
   }

This would require a slight modification to the container and could be extended by the use of Func<T, Tn, TResult>(T value, Tn valuen).  The container would match the parameters to a suitable constructor.

This is quite a powerful and time saving concept but I don’t like the vagueness of Func(), it’s not as expressive as it could be.  So the method I have chosen for DirLinker is to use strongly typed delegates and generate them at runtime from the container.   It works in the same manner only you declare the delegate up front and pass them in as an argument.  This, also, requires a bit of configuration but the pay off is worth it.  I have started work on the implementation for DirLinker so this example is taken directly from the unit tests and can be found here.

interface ITestClassWithDelegateFactory { ITestClassFactory Factory { get; set; } }
delegate ITestClass ITestClassFactory();  
class TestClassWithDelegateFactory : ITestClassWithDelegateFactory
{
     public ITestClassFactory Factory { get; set; }
     public TestClassWithDelegateFactory(ITestClassFactory delegateFactory)
     {
         Factory = delegateFactory;
     }
}  
[Test]
public void ManufactureType_Type_delegate_factory_manufactures_correct_type()
{
    IClassFactory testClassFactory = new ClassFactory();  
    testClassFactory.RegisterType<ITestClass, TestClass>()
                .WithFactory<ITestClassFactory>();  
    testClassFactory.RegisterType<ITestClassWithDelegateFactory, TestClassWithDelegateFactory>();  
    ITestClassWithDelegateFactory manufacturedType =
            testClassFactory.ManufactureType<ITestClassWithDelegateFactory>();
    ITestClass instance = manufacturedType.Factory();  
    Assert.IsInstanceOf(typeof(TestClass), instance);  
}

Admittedly there is quite a lot going on here but the main points are we registered a type and factory in a strongly typed manner with the container. Then pull it out and use it to create an instance of a different type.  I am going to cover this in quite some detail along with the how to create strongly typed delegates at runtime in my next post.

Comments