When to lazy load?
Asked Answered
F

9

9

I lazy load all my members. I have been doing this for a while and simply taken lazy load to be a good thing at face value.

Let's say we have

public class SomeClass
{
   public int anInt;
   public SomeReferenceType member1;

   public SomeClass()
   {
      //initialize members in constructor when needed (lazy load)
      anInt = new int();
      member1 = new SomeReferenceType();
   }
}

Are there any disadvantages to doing things this way? Is this a proper lazy load pattern? Does it make sense to lazy load a value type (with modern RAM does it even matter)?


After what I have learned from your answers, I would like to know if there is any difference between the above and this...
public class SomeClass
    {
       public int anInt;
       public SomeReferenceType member1 = new SomeReferenceType();

       public SomeClass()
       {

       }
    }
Frankie answered 13/10, 2011 at 13:39 Comment(9)
Your code sample is eager loading.Endue
I don't think initializing in the constructor is lazy loading.Novanovaculite
I don't think it matters, but look out when you have multiple constructors, if you forget to put member1 = new balbal you'll get nullreference when trying to use the variable. And btw there is no need to use new int() i believeVidar
Personally I only use lazy loading if loading es really expensive and it's likely the property in question will never be used.Endue
Lazyloading is loading when needed, not when creating an objcect. There is no need to create an integer with new.Pedi
Please don't prefix your titles with "c#". In reading your title, it's necessary to parse past the "C#" before getting to the actual title.Adrianneadriano
@John - I do this because I tend to get less questions regarding "which language is this" and fewer inappropriate answers (and I do tag the questions).Frankie
I would be surprised to find that this is true, at least among users who have been using Stack Overflow for a while. I imagine it might be true of those who don't know what the tags are for. In any case, they've begun removing the obvious cases, like "[C#] Title", and I think your style might not be long for it.Adrianneadriano
@John - Ok, I'll stop doing it then.Frankie
C
18

First of all, initializing a member inside the constructor isn't lazy loading.

Lazy Loading is initializing the member the first time it is requested. A simple example in .NET (with some double-check locking so we don't have threading issues):

public class SomeClass
{
    private object _lockObj = new object();
    private SomeReferenceType _someProperty;

    public SomeReferenceType SomeProperty
    {
        get
        {
            if(_someProperty== null)
            {
                lock(_lockObj)
                {
                    if(_someProperty== null)
                    {
                        _someProperty= new SomeReferenceType();
                    }
                }
            }
            return _someProperty;
        }
        set { _someProperty = value; }
    }
}

Luckily, if you're using .NET 4, you can now user the Lazy<T> Class which handles the issues for you and makes things a lot easier.

Second of all, lazy loading is a good idea when you have many members that could be costly to load and you're sure that you're going to be using all of those values. That cost would cause the type to be un-necessarily slow to instantiate.

Lazy Loading just for the sake of lazy loading is adding unnecessary complexity to your code and could cause issues down the road if done improperly (when dealing with threading, for example).

Cephalo answered 13/10, 2011 at 13:42 Comment(1)
An often overlooked common side-effect of lazy loading (depending on context) is it's effect on user experience. Sometimes when you wait to load something until a user needs it, it negatively impacts the perceived responsiveness of the application. Profiling metrics are invaluable when making decisions like this.Meehan
S
9

That's not really a lazy load. That's initializing on construction. Typically what we mean in lazy loading is to construct the item the first time it's referenced.

    private string _someField;

    public string SomeField
    {
        get 
        {
            // we'd also want to do synchronization if multi-threading.
            if (_someField == null)
            {
                _someField = new String('-', 1000000);
            }

            return _someField;
        }
    }

It used to be one of the typical ways to Lazy load was a check,lock,check so that you don't lock if it's already created, but since it's possible for two items to pass the check and wait for the lock, you check again in the lock:

public class SomeClass
{
    private string _someField;

    private readonly object _lazyLock = new object();


    public string SomeField
    {
        get 
        {
            // we'd also want to do synchronization if multi-threading.
            if (_someField == null)
            {
                lock (_lazyLock)
                {
                    if (_someField == null)
                    {
                        _someField = new String('-', 1000000);
                    }
                }
            }

            return _someField;
        }
    }
}

There are various ways to do this, in fact in .NET 4.0, there is a Lazy<T> type that can help you do thread-safe lazy-loading easily.

public class SomeClass
{
    private readonly Lazy<string> _someField = new Lazy<string>(() => new string('-', 10000000), true);

    private readonly object _lazyLock = new object();


    public string SomeField
    {
        get
        {
            return _someField.Value;
        }
    }
}

As to the why, typically lazy-loading is a good scheme if the object you are creating tends to be expensive (memory or time) and there's no guarantee you'll need it. If you are reasonably sure it will always be used, then you should just construct it outright.

Scherle answered 13/10, 2011 at 13:43 Comment(2)
You should mention that your construct only works if SomeField (which is a property, not a field :-p) is never actually null. It is easy to conceive a case in which the result of a heavy computation may genuinely be null and you want to be able to store that.Apposition
@Timwi: Oh sure, I was just using a simplistic example. For some things, null is an acceptable value. But usually in that case there's not much need to lazy-load.Scherle
M
6

From the code I am seeing, you are not doing lazy load. You are initializing members in the constructor, which always happens and happens very soon in the lifetime of the instance.

Hence, I am wondering, what is not-lazy loading for you?

Lazy loading is usually when you only initialize something when you are accessing it.

Here an example, using .NET 4.0 Lazy class, which helps you in doing just that, lazy loading:

public class Foo
{
    private Lazy<int> _value = new Lazy<int>(() => 3);

    public int Value { get { return _value.Value; } }
}

Regarding thread-safety - you can pass a second argument LazyThreadSafetyMode which knows two ways to specify thread-safety: One in which execution of the initialization method may happen several times, but where all threads get the value that was created first, or one where the execution is also protected against being run several times.

Mcclanahan answered 13/10, 2011 at 13:42 Comment(2)
I know I need to initialize reference types in the constructor or I'll get a null reference exception. Are you saying that I do not need to explicitly initialize value types? They are somehow, automatically initialized when the constructor is called? If yes, is there a term for this action?Frankie
That's simply initializing. The default initialization sets all instance fields to its default (null for reference types, the default for value types). Lazy loading explicitly means instantiating sth. the latest possible, which is when it a resource is accessed.Mcclanahan
B
1

Example with/without Lazy Loading

Consider that one Author may have zero to multi Books

Without Lazy Loading:

public class Author
{
public int Id {get;set;}
public string Name  {get;set;}
public Icollecation<Book> Books {get;set;}

}

public class Book
{
public int Id {get;set;}
public string Title{get;set;}
public Author Author {get;set;}
public int yearOfrelease {get;set;}

}

// Get the info from books, consider my view has book name, title, author name
await _context.Books.ToListAsync();

this will bring the following result

Book name Title Author Year
Book1 Title1 2022
Book2 Title2 2021

We can see that the author is empty. To load the author i need to add include()

await _context.Books.include(a=>a.Author).ToListAsync();

now I get the following :

Book name Title Author Year
Book1 Title1 Author1 2022
Book2 Title2 Author2 2021

This is what we call it eager loading

With lazy loading I MUST add virtual to related tables

public class Author
{
public int Id {get;set;}
public string Name  {get;set;}
public virtual Icollecation<Book> Books {get;set;}

}

public class Book
{
public int Id {get;set;}
public string Title{get;set;}
public virtual Author Author {get;set;}
public int yearOfrelease {get;set;}

}

now just call the books you will get all the related data

await _context.Books.ToListAsync();
Book name Title Author Year
Book1 Title1 Author1 2022
Book2 Title2 Author2 2021

In another word, in lazy loading, we delay the loading of the object until the point where we need it. so with lazy loading, we load all the books info regardless you want to use them or not.

Brickle answered 19/12, 2022 at 14:45 Comment(0)
R
0

this is not lazy loading.

lazy loading would mean that you just load the value at the moment of a real access (which doesnt happen in the initializer)

lazy loading is something like that:

private SomeClass _someRef = null;
public SomeClass SomeRef
{
  get
  {
    if(_someRef == null)
    {
       //initialisation just in case of access
       _someRef = new  SomeClass();
    }
    return _someRef;
  }
}
Rebekah answered 13/10, 2011 at 13:44 Comment(1)
You should mention that your construct only works if SomeRef is never actually null. It is easy to conceive a case in which the result of a heavy computation may genuinely be null and you want to be able to store that.Apposition
A
0

A real lazy-loaded property for an int might look something like this:

private int? _heavyLoadedInt;

public int HeavyLoading
{
    get
    {
        if (_heavyLoadedInt == null)
            _heavyLoadedInt = DoHeavyLoading();
        return _heavyLoadedInt.Value;
    }
}

Now if you look at this, you’ll see that there is some overhead here: You have to store the value in a nullable (extra memory); check it for null at every access, and retrieve the value from the nullable at every access.

If your integer really requires some seriously heavy computation, then this construct makes sense. But new int() is not a heavy computation, it just returns 0. The overhead is tiny, but if you add this overhead to an even tinier operation (which is to read an integer), it makes no sense.

Apposition answered 13/10, 2011 at 13:49 Comment(1)
here you also have to mention that nullable works only on value types... so your construct makes sense for heavy computing for a value type but not for expensive (big) reference typesRebekah
V
0

Lazy loading is essential when the cost of object creation is very high and the use of the object is vey rare. So, this is the scenario where it's worth implementing lazy loading. The fundamental idea of lazy loading is to load object/data when needed

Viral answered 15/9, 2017 at 12:22 Comment(0)
I
0

Lazy loading is a concept where we delay the loading of the object until the point where we need it. Putting in simple words, on demand object loading rather than loading objects unnecessarily.

For example, consider the below example where we have a simple Customer class and this Customer class has many Order objects inside it. Have a close look at the constructor of the Customer class. When the Customer object is created it also loads the Order object at that moment. So even if we need or do not need the Order object, it’s still loaded.

Link to Example

Immoderate answered 8/8, 2018 at 9:37 Comment(1)
add the image properly please, better : add code instead of the imageAmphi
P
0
List<int> number = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        var result = number.Where(x => x % 2 == 0);
        number.Add(20);
        //foreach (int item in result)
        //{
        //    Console.WriteLine("loop1:" + item);
        //}

        foreach (int item in result)
        {
            if (item == 4)
                break;
            Console.WriteLine("loop2:" + item);
        }
        number.Add(40);
        foreach (int item in result)
        {

            Console.WriteLine("loop3:"+item);
        }
        Console.ReadLine();

uncomment first loop and see the difference. very using example to under stand deffred execution and lazy loading.

Poitiers answered 28/9, 2018 at 9:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.