How yield
implements the pattern of lazy loading
?
To lazy load an image, display a lightweight placeholder image, and replace with the real full-size image on scroll. There are several technical approaches to lazy loading images: Inline <img> tags, using JavaScript to populate the tag if image is in viewport. Event handlers such as scroll or resize.
There are four common ways of implementing the lazy load design pattern: lazy initialization; a virtual proxy; a ghost, and a value holder.
The Virtual Proxy pattern is a memory saving technique that recommends postponing an object creation until it is needed. It is used when creating an object the is expensive in terms of memory usage or processing involved.
Lazy loading in Entity Framework is the default phenomenon that happens for loading and accessing the related entities. However, eager loading is referred to the practice of force-loading all these relations.
Lazy loading is the process whereby an entity or collection of entities is automatically loaded from the database the first time that a property referring to the entity/entities is accessed. Lazy loading means delaying the loading of related data, until you specifically request for it.
yield implementation doesn't reach the code until it's needed.
For example, this code:
public IEnumerable<int> GetInts()
{
yield return 1;
yield return 2;
yield return 3;
}
Will actually compile into a nested class which implements IEnumerable<int>
and the body of GetInts()
will return an instance of that class.
Using reflector you can see:
public IEnumerable<int> GetInts()
{
<GetInts>d__6d d__d = new <GetInts>d__6d(-2);
d__d.<>4__this = this;
return d__d;
}
Edit - adding more info about GetInts
implementation:
The way this implementation makes it lazy is based on the Enumerator
MoveNext()
method. When the enumerable nested class is generated (<GetInts>d__6d
in the example), it has a state and to each state a value is connected (this is a simple case, in more advanced cases the value will be evaluated when the code reach the state). If we take a look in the MoveNext()
code of <GetInts>d__6d
we'll see the state:
private bool MoveNext()
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
this.<>2__current = 1;
this.<>1__state = 1;
return true;
case 1:
this.<>1__state = -1;
this.<>2__current = 2;
this.<>1__state = 2;
return true;
case 2:
this.<>1__state = -1;
this.<>2__current = 3;
this.<>1__state = 3;
return true;
case 3:
this.<>1__state = -1;
break;
}
return false;
}
When the enumerator is asked for the current object it returns the object which is connected to the current state.
In order to show that the code is evaluated only when it's required you can look at this example:
[TestFixture]
public class YieldExample
{
private int flag = 0;
public IEnumerable<int> GetInts()
{
yield return 1;
flag = 1;
yield return 2;
flag = 2;
yield return 3;
flag = 3;
}
[Test]
public void Test()
{
int expectedFlag = 0;
foreach (var i in GetInts())
{
Assert.That(flag, Is.EqualTo(expectedFlag));
expectedFlag++;
}
Assert.That(flag, Is.EqualTo(expectedFlag));
}
}
I hope it's a bit more clear. I recommend to take a look at the code with Reflector and observe the compiled code as you change the "yield" code.
If you want to know more about what the compiler is doing when using yield return
, check this article by Jon Skeet: Iterator block implementation details
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With