Lazy <T> disadvantages?
I recently started using Lazy throughout my application, and I was wondering if there are any obvious negative aspects that I need to consider when using Lazy<T> ?
I try to use Lazy<T> as often as I think it is necessary, first of all to reduce the memory size of our loaded but inactive plugins.
I will talk a bit about my comment, which reads:
I just started using Lazy and found that it often indicates poor design; or laziness on the part of the programmer. In addition, one drawback is that you must be more vigilant variables and create the correct closure.
For example, I used Lazy<T> to create pages that the user can see in my (session) MVC application. This is the control wizard, so the user may want to go to the random previous step. When a handshake is performed, the array of Lazy<Page> objects is broken into pieces, and if the user specifies as a step, then the exact page is evaluated. I find it provides good performance, but there are some aspects that I don’t like, for example, many of my foreach constructs now look like this:
foreach(var something in somethings){ var somethingClosure = something; list.Add(new Lazy<Page>(() => new Page(somethingClosure)); } those. You must deal with the closure problem very actively. Otherwise, I don’t think that such poor performance hit to store lambda and evaluate it if necessary.
On the other hand, this may indicate that the programmer is Lazy<Programmer> , in the sense that you prefer not to think through your program now, but instead let the correct logic evaluate when necessary, as in the example in my case - instead of building this array, I could just find out exactly what this requested page will be; but I decided to be lazy and do everything in the call.
EDIT
It seems to me that Lazy<T> also has several features when working with concurrency. For example, for some scenarios, there is a ThreadLocal<T> and several flag configurations for your particular multi-threaded script. You can read more at msdn .
This is not a completely negative aspect, but for lazy people :).
Lazy initializers are like static initializers. They get it once . If an exception is thrown, the exception is cached and subsequent calls to .Value will throw the same exception. This is by design and is mentioned in the docs ... http://msdn.microsoft.com/en-us/library/dd642329.aspx :
Exceptions thrown by the Factory value are cached.
Therefore, the code as shown below will never return a value:
bool firstTime = true; Lazy<int> lazyInt = new Lazy<int>(() => { if (firstTime) { firstTime = false; throw new Exception("Always throws exception the very first time."); } return 21; }); int? val = null; while (val == null) { try { val = lazyInt.Value; } catch { } } In my opinion, you should always have a reason to choose Lazy. There are several alternatives depending on the use case, and there are certain cases when this structure is suitable. But do not use it just because it is cool.
For example, I don’t understand the point in the page selection example in one of the other answers. Using a Lazy list to select a single item can be done using a list or delegate dictionary directly without using Lazy or with a simple switch statement.
Thus, the most obvious alternatives are
- direct authority for cheap data structures or structures that are necessary anyway
- delegates for things that are needed from zero to several times in some algorithm
- some caching structure for elements that should free memory when not in use for a while
- some kind of "future" structure, such as the "Task", which can already start initializing asynchronously before actual use, consuming simple processor time in cases where the probability is high enough that the structure will be needed later
In contrast, Lazy often comes up when
- computationally intensive data structures
- in a null algorithm, a null value has a null value, and a null case has a significant probability
- and the data is local to a method or class and can be garbage collected if it is no longer used, or the data must be stored in memory for the entire duration of the program.
I came to use Lazy<T> mainly because of its concurrency capabilities when loading resources from a database. Thus, I got rid of the lock objects and possible lock patterns. In my case, ConcurrentDictionary + Lazy as the value made by my day, thanks @Reed Copsey and his blog post
This is as follows. Instead of calling:
MyValue value = dictionary.GetOrAdd( key, () => new MyValue(key));Instead, we will use ConcurrentDictionary> and write:
MyValue value = dictionary.GetOrAdd( key, () => new Lazy<MyValue>( () => new MyValue(key))) .Value;
It is noted that minus Lazy<T> .
As with everything, Lazy<T> can be used for good or evil, so the disadvantage is that if used improperly, it can cause confusion and frustration. However, a lazy initialization scheme has been around for many years, and now that .NET BCL has developers, developers do not need to reinvent the wheel. What more, MEF loves Lazy .
What exactly do you mean "throughout my application"?
I think that it should be used only when you are not sure whether this value will be used or not, which can take place only with additional parameters that take a lot of time to calculate. This may include complex calculations, file processing, web services, database access, etc.
On the other hand, why use Lazy here? In most cases, you can just call the method instead of lazy.Value , and that doesn't make any difference. BUT for a programmer it’s easier and more understandable what happens in this situation without Lazy .
One obvious potential may already be realized by caching the value, but I don't think this is such a big advantage.
Lazy is used to conserve resources while they are not needed. This template is pretty good, but the implementation may be useless.
The larger the resource, the more useful this template.
Failure to use the Lazy class - opacity of use. Indeed, you must maintain additional indirection (.Value) throughout. When you just need an instance of a real type, it is forced to load, even if you do not need to use it directly.
Lazy gains productivity for lazy development, but this gain can be lost with high use.
If you have a real transparent implementation (for example, using a proxy template), it gets rid of disavantage and can be very useful in many cases.
Concurrency should be considered in another aspect and not implemented by default in your type. It should only be included in client code or use type helpers for this concept.