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?

Acaz Souza
  • 8,311
  • 11
  • 54
  • 97

3 Answers3

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; }
}
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • Some serialization mechanisms bypass the constructor. – Dmitri Nesteruk Mar 11 '14 at 14:58
  • Lazy is thread safe so you'd better use Lazy. – marbel82 Jan 19 '21 at 15:42
  • While it's true that `Lazy` 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. – Daniel Hilgarth Jan 19 '21 at 15:44
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; } }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • if i want to do MyInstance.Questions = new List { ... } ? – Acaz Souza Jul 27 '11 at 13:42
  • @Acaz: Then what benefit is `Lazy` giving you? It's really not clear what you're trying to accomplish having both a setter *and* lazy initialization. – Jon Skeet Jul 27 '11 at 13:45
  • avoid to do that: public IList Questions { get { return _questions == null ? new List : _questions; } } – Acaz Souza Jul 27 '11 at 13:48
  • 1
    @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? – Jon Skeet Jul 27 '11 at 13:55
  • Nothin reason, only to beauty of my code. I think i will change to a simple solution without Lazy class. – Acaz Souza Jul 27 '11 at 14:15
  • 9
    @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. – Joshua Frank Dec 01 '11 at 19:15
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; } }
George R
  • 3,784
  • 3
  • 34
  • 38