In .NET 4 the following snippet with a cached property can also be written using the System.Lazy<T>
class. I measured the performance of both approaches and it's pretty much the same. Is there any real benefit or magic for why I should use one over the other?
Cached Property
public static class Brushes
{
private static LinearGradientBrush _myBrush;
public static LinearGradientBrush MyBrush
{
get
{
if (_myBrush == null)
{
var linearGradientBrush = new LinearGradientBrush { ...};
linearGradientBrush.GradientStops.Add( ... );
linearGradientBrush.GradientStops.Add( ... );
_myBrush = linearGradientBrush;
}
return _myBrush;
}
}
}
Lazy<T>
public static class Brushes
{
private static readonly Lazy<LinearGradientBrush> _myBrush =
new Lazy<LinearGradientBrush>(() =>
{
var linearGradientBrush = new LinearGradientBrush { ...};
linearGradientBrush.GradientStops.Add( ... );
linearGradientBrush.GradientStops.Add( ... );
return linearGradientBrush;
}
);
public static LinearGradientBrush MyBrush
{
get { return _myBrush.Value; }
}
}
Lazy<T>
will correctly handel concurrent scenarios (if you pass in the correct LazyThreadSafetyMode ) while your example does not have any thread-safety checks.Use
Lazy<T>
, as it expresses exactly what you are doing - lazy loading.In addition, it keeps your property very clean and is thread safe.
Lazy has some syncronization overhead to provide thread-safety whereas cached property is initiliazed by CLR way before any other code and you do not need to pay synronization cost
From a testability point of view, Lazy is well tested and proven artifact.
However, it has a very slight overhead, in my opinion, over other option
I would use
Lazy<T>
in general:Note that you don't have to use a lambda expression for the delegate. For example, here's an approach which may be slightly cleaner:
This is particularly handy when the creation process gets complicated with loops etc. Note that by the looks of it, you could use a collection initializer for
GradientStops
in your creation code.Another option is not to do this lazily, of course... unless you have several such properties in your class and you only want to create the relevant objects on a one-by-one basis, you could rely on lazy class initialization for many situations.
As noted in DoubleDown's answer, there's no way of resetting this to force recomputation (unless you make the
Lazy<T>
field not readonly) - but I've very rarely found that to be important.Typically the only reason to not use lazy is to reset the variable to null so the next access causes it to load again. Lazy has no reset and you'd need to recreate the lazy from scratch.
The
Lazy<T>
is simpler—it clearly expresses the intent of the code.It's also thread safe.
Note that if you're actually using this on multiple threads, you need to make it
[ThreadStatic]
; GDI+ objects cannot be shared across threads.