How to use System.Lazy with Setter to Lazy Initialization of List in POCO Entities?
Asked Answered
J

3

18

I want to use System.Lazy to Lazy Initialization of my List in my Entites:

public class Questionary
{
    private Lazy<List<Question>> _questions = new Lazy<List<Question>>(() => new List<Question>());

    public IList<Question> Questions { get { return _questions.Value; } set { _questions.Value = value; } }
}

The problem is on my SETTER, get this error: The property 'System.Lazy<T>.Value' has no setter

If i want to do MyInstance.Questions = new List<Question> { ... } ?

How do I proceed?

Update:

I'm trying to avoid that:

private IList<Question> _questions;

//Trying to avoid that ugly if in my getter:
public IList<Question> Questions { get { return _questions == null ? new List<Question>() : _questions; } set { _questions = value } }

I'm doing something wrong?

June answered 27/7, 2011 at 13:37 Comment(0)
C
26

You could do something like this:

public class Questionary
{
    private Lazy<IList<Question>> _questions = 
        new Lazy<IList<Question>>(() => new List<Question>());

    public IList<Question> Questions
    {
        get { return _questions.Value; }
        set { _questions = new Lazy<IList<Question>>(() => value); }
    }
}

However, I don't see why you need Lazy<T> here at all. There is no benefit in using it, because the initialization of a new List<T> should be the same as the initialization of a new Lazy<T>...

I think it would be enough to keep it as simple as this:

public class Questionary
{
    private IList<Question> _questions = new List<Question>();

    public IList<Question> Questions
    {
        get { return _questions; }
        set { _questions = value; }
    }
}

or

public class Questionary
{
    public Questionary()
    {
        Questions = new List<Question>();
    }

    public IList<Question> Questions { get; set; }
}
Coheman answered 27/7, 2011 at 13:42 Comment(3)
Some serialization mechanisms bypass the constructor.Bowhead
Lazy is thread safe so you'd better use Lazy.Genome
While it's true that Lazy<T> is thread-safe, it doesn't make any difference here. The _questions variable isn't static and it will be initialized when creating a new instance of the Questionary class. And creating a new instance always is happening on a single thread.Coheman
S
6

It's not clear what you're trying to do. You can't set the value of a Lazy<T> - it's as simple as that. You can only ask it for a value, and it will execute the delegate you've provided the first time the values are requested.

Do you really need a setter in your class at all? Perhaps you just want:

public class Questionary
{
    private Lazy<List<Question>> _questions = 
        new Lazy<List<Question>>(() => new List<Question>());

    public IList<Question> Questions { get { return _questions.Value; } }
}
Secundas answered 27/7, 2011 at 13:40 Comment(6)
if i want to do MyInstance.Questions = new List<Question> { ... } ?June
@Acaz: Then what benefit is Lazy<T> giving you? It's really not clear what you're trying to accomplish having both a setter and lazy initialization.Secundas
avoid to do that: public IList<Question> Questions { get { return _questions == null ? new List<Question> : _questions; } }June
@Acaz: But now you haven't got a setter... do you really want it to be both self-initializing and allow a setter? Any reason you don't just assign a list in the constructor?Secundas
Nothin reason, only to beauty of my code. I think i will change to a simple solution without Lazy class.June
@JonSkeet: I have this problem too, and the reason I want both a setter and a lazy load is this: I've got Person objects, and each Person has an Address. I often want to use the Person object for its Id and Name, and set up the Address to lazy-load from the database when needed. But I also have a view where I need to show a list of people with their addresses, and in this case I fetch all the people and their addresses in a single sql statement with a join, and I want to initialize each person along with his/her address, and NOT have the address lazy-load, making a db call each time.Perimeter
L
2

Non-lazy solution - same benefit in terms of being initialized only when called:

    private List<Question> _questions;
    public List<Question> Questions { get { return _questions ?? (_questions = new List<Question>()); } set { _questions = value; } }
Lakshmi answered 12/11, 2012 at 2:30 Comment(2)
This isn't thread-safe, though, which is something that you get for free with Lazy<T>.Necking
Not 'free' from a performance perspective, but free from a lines-of-code perspective ;)Headsail

© 2022 - 2024 — McMap. All rights reserved.