0

Using Lazy<T> property caching, is there any behavioural differences between accessing the property with a backing field or without the backing field? Perhaps any performance hits?

The example code below is caching Autofac IoC container in an internal property. The code is only meant to be initialized once. Whether it does or does not follow the right IoC / DI principles is not the question.

Example 1:

internal static ILifetimeScope Bootstrap = new Lazy<ILifetimeScope>(InitializeContainer, LazyThreadSafetyMode.ExecutionAndPublication).Value;

private static ILifetimeScope InitializeContainer()
{
    ContainerBuilder builder = new ContainerBuilder();
    //Registration logic...
    return builder.Build();
}

Example 2:

private static readonly Lazy<ILifetimeScope> _container = new Lazy<ILifetimeScope>(InitializeContainer, LazyThreadSafetyMode.ExecutionAndPublication);

internal static ILifetimeScope Container => _container.Value;

private static ILifetimeScope InitializeContainer()
{
    ContainerBuilder builder = new ContainerBuilder();
    //Registration logic...
    return builder.Build();
}

Edit 1 I'm mostly interested in having a cached value of the container, so that it doesn't get initialized each time i access the property. I don't care if the initialization is deferred.

Thomas T
  • 697
  • 1
  • 7
  • 19
  • "Whether it does or does not follow the right IoC / DI principles is not the question." Not the question, but always something that is good to question. – Steven Feb 21 '17 at 13:02
  • Not much. I've tried accessing the property in both examples, and made sure it's only running the initialization factory once. Many 'Lazy' caching examples are shown with a backing field, and I wonder why, since I think the first example is prettier. E.g. http://stackoverflow.com/questions/5134786/cached-property-vs-lazyt?rq=1 – Thomas T Feb 21 '17 at 13:09
  • 2
    The first one is mostly equivalent to writing just `Bootstrap = InitializeContainer();`. It doesn't delegate the initialization to the time you access the container, just the time the static constructor for the containing class runs. There's little point in using `Lazy` in such a case. – Luaan Feb 21 '17 at 13:35
  • I'm mostly interested in having a cached value. Writing Bootstrap = InitializeContainer(); will initialize it each time i access it. – Thomas T Feb 21 '17 at 13:37
  • 2
    @ThomasT no it won't, why would you think that? `InitializeContainer` will execute once and the result will be stored in `Bootstrap`. I agree with @Luaan here, if you don't care about deferred execution, just create it early in the lifetime of your app and store it in an accessible property. – Mickaël Derriey Feb 21 '17 at 22:32

1 Answers1

2

IMO in the first example calling .Value on that line makes Lazy almost useless, because it is instantiating the container at the very next time that the lazy object is instantiated, so what is the point of doing it Lazy if the creation of the object is not deferred to a later time.

So, if you need to defer the creation of the object then the second example I think is better because the container won't be initialized until the first moment that Container gets called.

Another example would be a field that doesn't do .Value on the end so it is the same as the second example but you have to call .Value anywhere you want to use it, making it a little uncomfortable.

internal static Lazy<ILifetimeScope> Bootstrap = new Lazy<ILifestimeScope>(InitializeContainer, LazyThreadSafetyMode.ExecutionAndPublication);

So if I were in your place I'd go for the second example is both comfortable to call and makes useful the Lazy loading, but remember that the first time to call it will initialize the container so the first time to use it will take a little more time than the first example to complete the action

fmaccaroni
  • 3,846
  • 1
  • 20
  • 35
  • I'm mostly interested in having a cached value and not defering the creation. – Thomas T Feb 21 '17 at 13:39
  • Then it's pretty much the same, but I'd evaluate if your container has to be thread safe. If this is so, then use Lazy, if not, you can use a static constructor; Lazy has a little overhead over the static ctor but ensures the thread safety if configured properly. And between the two examples I don't think there is a significant hit on the performance on using one or the other – fmaccaroni Feb 21 '17 at 14:20