What is not so clear in all of this is that this class should be used whenever the data may or may not be used in the execution of the moment. It’s not just a question of leaving it for later, it’s a question of leaving it for later because who knows it might not even be necessary.
I think it’s clear that it’s only worth doing this if the startup is expensive, so it comes from an expensive operation of a database, or from the internet or service that you have no control over the time spent. It’s kind of the use of async
, is only worth it if the operation takes.
In general fields of a structure are initialized at the time of its creation so any situation that it may or may not be used can be useful.
But you have to be careful because people can start using this to make up for design bad. There is situation that what may or may not be used, and therefore delayed, must be part of another object.
Examples
The most common example of using this type is in Orms since the data may or may not be used so it would be better not to ask DB right away. On the other hand, and this is one of the criticisms of the ORM, this can hurt performance because it makes you have more access to the database instead of bringing it all at once. Of course, normally you have it ready and you don’t use the Lazy
in your code, unless you’re doing an ORM, and yet you may even prefer a more sophisticated control mechanism, Lazy
is quite simple.
I found a example in the OS that shows well that everything that uses the Lazy
can do without it:
public sealed class Singleton {
private static readonly Lazy<Singleton> instanceHolder = new Lazy<Singleton>(() => new Singleton());
private Singleton() { ... }
public static Singleton Instance => instanceHolder.Value;
}
And without:
private static object lockingObject = new object();
public static LazySample InstanceCreation() {
if (lazilyInitObject == null) {
lock (lockingObject) {
if (lazilyInitObject == null) lazilyInitObject = new LazySample();
}
}
return lazilyInitObject;
}
I put in the Github for future reference.
I do not know if the example is so good to show the practice (the goal was not this) because the object is only created when it is called once and in this case usually when it calls already needs to be used.
It is the same case of local use (method), you can put in the moment you need. I do not say you should never use, but in general do not need the Lazy
. The need for this type has more to do with the fact that you don’t know the exact moment you need. Almost all examples of local use is only to demonstrate the mechanism and not the practice of use.
If you have a static object it can be useful because by specification the initialization of that object can be done at any time from the initialization of the application to the use of that object. The Lazy
would be a way to ensure that effective startup occurs only at the time of use.
This is because formal initialization occurs without your control, but what is initialized is object Lazy
which is very cheap, and the object that matters (the T
) will be initialized when used, The Lazy
controls this.
So trying to make a practical use, think that you access the data of a bank teller. In general you only access your account data, but in some cases you can access your account’s transactions, but for some reason the list of these transactions were placed in your account probably to facilitate access and not have an external object.
public Lazy<IList<Transacoes>> trancasoes => new Lazy<IList<Transacoes>>(() => ObtemTranscaoes(this.Id));
I assume that this method takes time to be executed.
Is it a good example? I guess not because it seems to be design bad only, but if you had any reason to keep the transactions close to the account then it makes sense. Most of the examples we find are not even necessary.
An example that can be useful is when there is memoisation. But it can also abuse this and in many cases needs a sophistication that the Lazy
does not solve. In others the time he spends is derisory to need lazy boot.
It’s like Pattern design (what this is already ready for use provided by the library), you should know it exists, but not quit applying because it exists. In the rare cases that must be used you have knowledge and will see that there apply, or else that your design is bad and should rethink it.
hum I’m still reading everything, but this example of Singleton is very interesting, much cleaner code
– Ricardo Pontual
Manieiro, this gave me an idea: imagine that you have a strategy that creates instances of classes, or a chain of methods, anything like that, and this strategy may take or may never be used, maybe it would be a good application for Lazy in creating the instances, makes sense?
– Ricardo Pontual
I do not know if I understood or if it is clear the details of how this would occur, but an object should have only one strategy. You have several possible strategies, but only one of them would be used (at least looking at one aspect of that object). So there’s no need to create the others, so you don’t have to initialize, it’s not a question of initializing later. Unless you’re talking about that even the chosen strategy may not be used, then it is independent of being a strategy, is the same example I used with this
IList
, and can be design wrong. And if you’re saying that within the strategy you can have a– Maniero
Lazy
for something of it, it has nothing to do with the strategy mechanism, and yes this one in particular may happen to need this.– Maniero
I don’t think I explained it well, I’ll try to put together a code to make it clearer
– Ricardo Pontual