jdavis
jdavis

Reputation: 8655

C# Property with hard coded getter and setter

I have a property defined as...

public List<Obj> Objs { get; set; }

What I would like to be able to do is to put some logic into the get method, so it would look something like...

public List<Obj> Objs
{
    get
    {
        if (Objs == null)
        {
            Objs = new List<Obj>();
        }
        if (Objs.Count < 1)
        {
            Objs.Add(new Obj());
        }
        return Objs;
    }
    set { Objs = value; }
} 

Now when I do this I get an error telling me that the Function is recursive on all paths.

Is there a way to do this without creating a private backing field?

Upvotes: 6

Views: 8097

Answers (6)

paparazzo
paparazzo

Reputation: 45096

private List<Obj> objs = new List<Obj>() { new Obj() };
public  List<Obj> Objs { get { return objs; } }

or if you want to protect from someone removing the last Obj

private List<Obj> objs = new List<Obj>();
public List<Obj> Objs 
{ 
   get 
   { 
       if (objs.Count == 0) objs.Add(new Obj());
       return objs; 
   } 
}

What would be the purpose of a public set?

Upvotes: 0

Arve Systad
Arve Systad

Reputation: 5479

No, not really.

In your code, when you check for if (Objs == null) - you are effectively using the get method in which you are currently in. So Objs { get; } calls itself, and that's why it's always recursive.

Remember that auto properties (get; set;) is really just a shorthand for having a backing field and separate get and set methods. Without that magic, your code would look like this:

private List<Obj> _objs;
public List<Obj> GetObjs() { return _objs; }
public void SetObjs(List<Objs> objs) { _objs = objs; }

What you are really implementing in your post is this - notice how GetObjs() is calling itself multiple times. So for every time it calls itself, it will eventually lead to it calling itself again. And again, and again.:

public List<Obj> GetObjs() {
    if (GetObjs() == null)
    {
        SetObjs(new List<Obj>());
    }
    if (GetObjs().Count < 1)
    {
        GetObjs().Add(new Obj());
    }
    return GetObjs();
}

Upvotes: 0

Jean-Philippe Leclerc
Jean-Philippe Leclerc

Reputation: 6795

You have to make a private field:

    private List<Obj> _objs;
    public List<Obj> Objs
    {
        get
        {
            if (_objs== null)
            {
                _objs= new List<Obj>();
            }
            if (_objs.Count < 1)
            {
                _objs.Add(new Obj());
            }
            return _objs;
        }
        set { _objs= value; }
    } 

Why is it impossible? Lets make the same thing in Java:

    private List<Obj> objs;
    public List<Obj> getListObjs()
    {
        ...
        // Recursion
        return getListObjs();
    }

Upvotes: 13

Erik Schierboom
Erik Schierboom

Reputation: 16636

Your property refers to itself in the definition of the get part of the property. This is illegal as it would cause the getter to end up in an endless loop. You either have a auto-implemented property (your first example), or a property with a backing field (which is automatically generated by the compiler for auto-implemented properties). You need to add a (preferrably private) field as a backing store for your property:

private List<Obj> objs;

public List<Obj> Objs
{
    get
    {
        if (objs == null)
        {
            objs = new List<Obj>();
        }
        if (objs.Count < 1)
        {
            objs.Add(new Obj());
        }
        return objs;
    }
    set { objs = value; }
} 

Upvotes: 1

Roman Bats
Roman Bats

Reputation: 1795

you should use private field to store List of Objs. You can't get data from get method of get method... :) is recursion.

private List<Obj> _objs;
public List<Obj> Objs
{
    get { 
    if (_objs== null)
    {
        _objs = new List<Obj>();
    }
    if (_objs.Count < 1)
    {
        _objs.Add(new Obj());
    }
    return _objs;
 }
    set { _objs= value; }
}

Upvotes: 0

Rune FS
Rune FS

Reputation: 21742

No there's no way of doing it without a backing field. Unrelated to the question but related to the situation. You should in general not expose a setter for a collection but only a getter. If you have a setter you are very often exposing internal state of the object, that should be kept hidden.

Upvotes: 3

Related Questions