Should Lazy<T> be preferred to lazy initialization in a getter?
Asked Answered
R

2

8

From .NET 4 onwards, Lazy<T> can be used to lazily initialize objects. Intuitively, lazy initialization can also be performed in a public property's getter to provide the same functionality to the caller. I wonder if Lazy<T> offers any inherent advantage over the latter and should thus be preferred?

Personally, I feel that Lazy<> can quickly reduce code readability, but perhaps I've just seen it misused. On a plus side, it ensures thread safety, but there are many .NET synchronization constructs that - perhaps I'm wrong - make it quite easy to achieve the same inside a getter.

What are some considerations to be aware of when choosing the best approach?

Raver answered 6/3, 2015 at 15:14 Comment(3)
Give an example of lazy initialization achieved without Lazy<T>. It's not so easy as you seem to think.Natascha
possible duplicate of Cached property vs Lazy<T>Isometropia
Default: missed that one, thanks. This can be marked as a duplicate. @Ben Voigt: similar as to what Patrick Hofman describes in his answer. Besides, I kindly ask people downvoting this to provide comments on how this question could be improved (got to say I'm kind of disappointed by how aggressive this site has become).Raver
A
10

Lazy<> can be useful since it inludes support for multithreading too, something you have to build yourself when creating your own 'lazy'.

For code that doesn't need multi-threading, this would be the best performing and readable code in my opinion (using the null-coalescing operator).

return variable ?? (variable = new ClassName());

Note that since this code isn't thread safe, you could end up calling new ClassName() multiple times.

You should introduce locking then, and the readability will decrease. If it is just for readability, Lazy<> might be not that bad in that case.

Also, Lazy<> prevents you to use the backing field in the case of cached properties.

Appreciable answered 6/3, 2015 at 15:19 Comment(7)
Yes, this is exactly how I would normally proceed to implement lazy loading in a getter - using the null-coalescing operator and some type of locking. To me it doesn't seem any less readable than introducing a bunch of lambda expressions etc., but of course that's subjective and can vary case-by-case. Otherwise, this makes perfect sense - thank you!Raver
@Raver I would never use "some type of locking" instead of using Lazy<T>, since Lazy<T> already does all that for you.Equivocate
@MatthewWatson: That was my argument too :)Appreciable
@Matthew Watson I'd argue that it depends on a use case. If you're not going to be using multithreading etc. I fail to see how either is different from the other. Of course, if the most general solution is desirable, then this makes sense.Raver
@Raver I'm explicitly talking about the case where you need to provide multithreaded safety. In the (perhaps unlikely) case that you don't know if you might need to add multithreaded support later on, then be aware that Lazy<T> lets you switch between threadsafe and non-threadsafe very easily.Equivocate
@Raver To be clear, I would NOT use Lazy<T> if I didn't need to provide thread safety (unless I thought it was probable that I had to add it some time in the future).Equivocate
@MatthewWatson thanks; this seems to me to be a good guideline.Raver
P
1

For a non-multithreaded purpose you can use the below safe getter:

private Foo? _variable;

public Foo Variable => _variable ?? (_variable = DoSomeHeavyTask()).Value;
Pitchdark answered 11/11, 2021 at 12:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.