Lazy loading, a life's bread of many developers, and a valuable tool for operation management.
THat being said there are a few ways to handle lazy loading, and with the advent of .Net 4.0 there is this wonderful nifty little Lazy<> generic class. However, given a few examples I question it's over head, as well as it's possible benefits
with complicated lazy evaluations. So to begin:
private MyClass _myClass;
public MyClass MyClass
{
get {
if (_myClass == null) _myClass = new MyClass();
return _myClass;
}
}
private Lazy<MyClass> _myClass = new Lazy<MyClass>();
public MyClass MyClass { get { return _myClass.Value; } }
Now between the two of them, the Lazy<> version still instantiates something regardless if you never access the MyClass property, where as the classic method will not instantiate anything until you reference MyClass and then it will create. Granted
there are Thread safe aspects within the Lazy<> class but let's not deal with that right now, as it isn't pertinent to my questions.
1. What kind of overhead does the Lazy<> class involve here? Negligible, minor, major, etc?
Now, there are also more complex lazy loads:
private MyClass _myClass;
public MyClass MyClass {
get {
if (_myClass == null) _myClass = new MyClass(this);
return _myClass;
}
}
private Lazy<MyClass> _myClass = new Lazy<MyClass>(() => new MyClass(this)); /*I may be wrong here because of the self
referencing during constructor creation or something, but hopefully not */
public Lazy<MyClass> MyClass {get { return _myClass.Value;}}
again these do the same thing, but again:
2. What is the overhead? (and does that 'this' referencing break the Lazy<> lambda or not)
Now for the real question.
Sometimes our lazy loading is more complex and not entirely adhering to a prerequisite that the resulting value will NEVER be null.
private MyComplexClass _myClass;
public MyComplexClass MyClass {
get {
if (_myClass == null) _myClass = this.CreateMyClass();
return _myClass;
}
}
private Lazy<MyComplexClass> _myClass = new Lazy<MyComplexClass>(() => this.CreateMyClass());
public Lazy<MyComplexClass> MyClass {
get {return _myClass.Value; }
}
protected MyComplexClass CreateMyClass() {
MyComplexClass mcc = null;
if (this.ShouldCreate) {
mcc = this.SomeCollection.FirstOrDefault(sc => sc.HasComplexValue);
}
return mcc;
}
Now, every time the classic version is referenced, if the _myClass field is null, the code to evaluate this.ShouldCreate is executed, as well as the .FirstOrDefault() lamba process is also executed EVEN WHEN THAT RESULTS IN NULL.
So the code that references this is fully aware that the MyClass property might be null, so that's okay. But, if I access this property a dozen times, a hundred times, and it never finds the value it's searching for, it will always keep executing those
code blocks. Sometimes this is the exact behavior we want. Other times we know that if it didn't find it the first time, it isn't going to so stop looking.
Think of the nullable type:
bool? _value;
public bool IsValue {
get {
if (!_value.HasValue) _value = this.DoSomeComplexEq();
return _value.Value;
}
}
public bool DoSomeComplexEx() {}
that scenario checks the "DoSomeComplexEq" has been run once. But it will never run it again (unless i set _value to null)
3. Does the Lazy<> system compensate for this process in a similar fashion, so that the "attempt" to create the object is only ever executed ONCE?
example (in a classic/manual fashion):
private bool _triedCreate;
private MyComplexClass _myClass;
public MyComplexClass MyClass {
get {
if (_myClass == null && !_triedCreate) {
_triedCreate = true;
_myClass = this.CreateComplexClass();
}
return _myClass;
}
}
public void ResetMyClassLazy() {
_triedCreate = false;
}
In this scenario, no matter how complex the evaluation is inside the this.CreateComplexClass() method, that method will only ever be executed once, until I call ResetMyClassLazy.
I am curious if the Lazy<> class system intrinsically handles this circumstance?
Thanks
Jaeden "Sifo Dyas" al'Raec Ruiner
"Never Trust a computer. Your brain is smarter than any micro-chip."
PS - Don't mark answers on other people's questions. There are such things as Vacations and Holidays which may reduce timely activity, and until the person asking the question can test your answer, it is not correct just because you think it is. Marking it
correct for them often stops other people from even reading the question and possibly providing the real "correct" answer.