Switching IoC Container with LINQ Expressions

Several last projects I used a simple IoC container, leveraging Activator.CreateInstance(type). The main reason - simplicity. Once there was a need to go to a higher level, I would switch to Windsor Container. One of the projects used Unity. The only issue was that I would always have to do some customization to my container (or DependencyResolver), which is nothing but a static gateway.

What I have decided, is that I do not want to invest effort in something that was working before just because the underlying implementation of container has changed. The container engine might be changed, but my code should not (OCP?). Therefore, DependencyResolver had to be coded slightly different. To make it possible, I decided to go with the LINQ Expressions. It allows to pass code in data structures, and thus allows to manipulate how to execute the code.

For demonstration purposes, I will only demonstrate the simple case, more complex cases are feasible as well.

   1: public interface IService
   2: {
   3:     void DoSomething();
   4: }
   6: public class ServiceImpl : IService 
   7: {
   8:     public void DoSomething()
   9:     {
  10:         Console.WriteLine("ServiceImpl");
  11:     }
  12: }

DependencyResolver (which is static gateway) is

   1: public static class DependencyResolver
   2: {
   3:     private static IDependencyResolver instance = new LambdaDependencyResolver();
   5:     public static void InitializeWith(IDependencyResolver resolver)
   6:     {
   7:         instance = resolver;
   8:     }
  10:     public static void Register<ContractType>(Expression<Func<ContractType>> func)
  11:     {
  12:         instance.Register(func);
  13:     }
  15:     public static ContractType Resolve<ContractType>()
  16:     {
  17:         return instance.Resolve<ContractType>();
  18:     }
  19: }

By default, LambdaDependencyResolver is going to be used. Registration is done by passing in an Expression<Func<ContractType>> that is nothing but a function that returns a ContractType implementer. The idea to wrap it with Expression, so that the instance (a particular dependency resolver implementation) would take care of the details based on how it works.

IDependencyResolver code

   1: public interface IDependencyResolver
   2: {
   3:     void Register<ContractType>(Expression<Func<ContractType>> func);
   4:     ContractType Resolve<ContractType>();
   5: }

LambdaDependencyResolver code

   1: public class LambdaDependencyResolver : IDependencyResolver
   2: {
   3:     private Dictionary<Type, object> dictionary = new Dictionary<Type, object>();
   5:     public void Register<ContractType>(Expression<Func<ContractType>> func)
   6:     {
   7:         if (dictionary.ContainsKey(typeof(ContractType)))
   8:         {
   9:             throw new InvalidOperationException(typeof(ContractType).FullName + " was added already to container.");
  10:         }
  12:         dictionary.Add(typeof(ContractType), func);
  13:     }
  15:     public ContractType Resolve<ContractType>()
  16:     {
  17:         if (!dictionary.ContainsKey(typeof(ContractType)))
  18:         {
  19:             throw new InvalidOperationException(typeof(ContractType).FullName + " was not found in container.");
  20:         }
  22:         var expression = dictionary[typeof (ContractType)];
  23:         var compiledLambda = ((Expression<Func<ContractType>>)expression).Compile();
  24:         return compiledLambda.Invoke(this);
  25:     }
  26: }

The usage

   1: DependencyResolver.Register<IService>(() => new ServiceImpl());
   2: var service = DependencyResolver.Resolve<IService>();
   3: service.DoSomething();

It's working, great. Some time later, we need to switch to some 3rd party container, and we don't want to change our code that relies on DependencyResolver. This is where Expressions are handy. I have used Unity container, but that could be StructureMap, Windsor Container, or anything else.

   1: public class UnityDependencyResolver : IDependencyResolver
   2: {
   3:     private UnityContainer container = new UnityContainer();
   5:     public void Register<ContractType>(Expression<Func<ContractType>> func)
   6:     {
   7:         var newExpression = (NewExpression)func.Body;
   8:         container.RegisterType(typeof (ContractType), newExpression.Type, new InjectionMember[] {});
   9:     }
  11:     public ContractType Resolve<ContractType>()
  12:     {
  13:         return (ContractType) container.Resolve(typeof(ContractType));
  14:     }
  15: }

Bolded code in LambdaDependencyResolver and UnityDependencyResolver is simply leveraging LINQ Expressions to make it all work. You can definitely make it more sophisticated and elegant as needed.


  • Some implementation there. I was thinking that your static gateway shouldn't expose a Register method but should keep the details of configuring the container elsewhere. If your LambdaDependencyResolver implemented IServiceLocator then you should be able to plug in other containers without needing to write adapters for those containers.

  • @Zelko,
    you are not quiet right about this. If the static gateway doesn't expose the Register, then in tests I have to rely on Container - doesn't sound right. Plus, how would you exactly implement the registration with other containers, if not leveraging expressions?

    DependencyResolver.Register(() => new ServiceImpl());

    You are more than welcome to submit a code sample ;)

Comments have been disabled for this content.