Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How yield implements the pattern of lazy loading?

How yield implements the pattern of lazy loading?

like image 672
masoud ramezani Avatar asked May 03 '10 08:05

masoud ramezani


People also ask

How do you implement 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.

Which design pattern can you use to implement lazy loading?

There are four common ways of implementing the lazy load design pattern: lazy initialization; a virtual proxy; a ghost, and a value holder.

Which design pattern can be used to implement lazy loading please choose only one answer?

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.

What is difference between lazy loading and eager loading?

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.

What is lazy loading in Entity Framework?

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.


2 Answers

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.

like image 128
Elisha Avatar answered Nov 06 '22 01:11

Elisha


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

like image 41
gammelgul Avatar answered Nov 06 '22 01:11

gammelgul