Tuesday 6 December 2011

Lazy Dependencies in C#

When using dependency injection you might get to a point where you need to supply a dependency on something that is expensive to create, for example:

  • A database connection
  • An object that takes long to create.

This would be fine if you were definitely using the dependency, but there are scenarios where the dependency might just sometimes be used.

Even though you can inject an abstract factory or a lambda function to evaluate the dependency, this didn’t feel so nice. And also felt like extra effort to define and also to manage the instance variable.

Then I found this post by Jeffrey Palermo explaining the exact same problem. I saw his solution and what I didn’t like about it is that he created a factory inside of a method in his class to create an OrderShipperFactory. With this refactoring it was not clear that the OrderProcessor now depends on the factory as it was not asking for it as a dependency. It is also not possible in this implementation to substitute a different factory. Jefferey went as far calling it constructor over-injection anti-pattern. A statement he relaxed in further posts.

But it turns out that this problem can be solved elegantly in .NET 4 with a new class called:

Lazy<T>

Lazy<T> solves this problem in 2 ways:

  • Lazy load the instance by automatically activating only when used.
  • Takes care of recycling the same instance variable.

Using lazy you only need to supply the type like this:

Code Snippet
  1. var lazy = new Lazy<Bar>();
  2.  
  3. // Value is initialized only when referenced for the first time
  4. Bar bar = lazy.Value;

Bar will automatically be created using reflection.

But you can also provide your own initializer like this:

Code Snippet
  1. new Lazy<Bar>(() => new Bar());

So to see this in action say we had a class called Foo with a dependency called Bar:

Code Snippet
  1. public class Foo
  2. {
  3.     private Bar _bar;
  4.     public Foo(Bar bar)
  5.     {
  6.         this._bar = bar;
  7.     }
  8.  
  9.     public void UseBar()
  10.     {
  11.         Console.WriteLine(string.Format("Using: {0}", _bar.GetType().FullName));
  12.     }
  13. }
  14.  
  15. public class Bar
  16. {
  17.     public Bar()
  18.     {
  19.         Thread.Sleep(3000);
  20.         Console.WriteLine("Bar created");
  21.     }
  22. }

But bar is expensive and takes 3 seconds to create.

If we create foo and supplied bar:

Code Snippet
  1. var sw = new Stopwatch();
  2. sw.Start();
  3. var foo = new Foo(new Bar());
  4. sw.Stop();
  5. Console.WriteLine(sw.ElapsedMilliseconds);
  6. foo.UseBar();

we would see this:

image

The construction takes 3 seconds.

If we replace this with:

Code Snippet
  1.  
  2. public class FooSolution
  3. {
  4.     private Lazy<Bar> _bar;
  5.     public FooSolution(Lazy<Bar> bar)
  6.     {
  7.         this._bar = bar;
  8.     }
  9.  
  10.     public void UseBar()
  11.     {
  12.         Bar bar = _bar.Value;
  13.         Console.WriteLine(string.Format("Using: {0}", bar.GetType().FullName));
  14.     }
  15. }

And used it like this:

Code Snippet
  1.  
  2. foo = new FooSolution(new Lazy<Bar>(() => new Bar()));
  3. foo.UseBar();

Now foo is created instantly and bar is only created when we actually use it

image

Now in case you are using an older version to .NET 4 you can create this class and then wrap it in a special compiler directive to only declare it for versions prior to this. A very nice stackoverflow post can be found here that explains how to set up this directive.

Here is an implementation of Lazy for pre .NET 4.0

Code Snippet
  1. #if NOT_RUNNING_ON_4
  2.     public class Lazy<T> where T : class
  3.     {
  4.         Func<T> _resolver;
  5.  
  6.         public Lazy(Func<T> resolver)
  7.         {
  8.             this._resolver = resolver;
  9.         }
  10.  
  11.         public Lazy()
  12.         {
  13.             this._resolver = () => Activator.CreateInstance<T>();
  14.         }
  15.  
  16.         T _instance = null;
  17.  
  18.         public T Value
  19.         {
  20.             get
  21.             {
  22.                 if (_instance == null)
  23.                 {
  24.                     _instance = this._resolver();
  25.                 }
  26.                 return _instance;
  27.             }
  28.         }
  29.     }
  30. #endif

What I like about Lazy over an injected factory here is that all we wanted was an instance to use when we needed it. A factory or Func<T> would give us a new instance each time and we would have to create a variable to manage the lifetime.

So it is still a good thing to use Dependency Injection, and most of the time I would not worry about this except if you have a specific performance need or a rare dependency that does have a significant creation hit.

dependency that does have a significant creation hit.

No comments:

Post a Comment