简体   繁体   中英

Property that is set only within protected constructor

I have following class, and wondering if declaring ListOfItems as public with a private setter is a proper way (from the OOP best practice point of view).

public abstract class Game
{
    public List<int> ListOfItemss { get; private set; }

    protected Game()
    {
    }

    protected Game(string gameInput)
    {
        ListOfItems = new List<int>();
        var gameParser = new GameParser();
        ListOfItems = gameParser.ParseGameInputString(gameInput);
    }

    public abstract int Bowl(int items);
}

Or should I made it via private field ie

public abstract class Game
{
    private List<int> _listOfItems;

    public List<int> ListOfItemss 
    {
            get { return _listOfItems; }
            private set { _listOfItems = value; }
        }

    protected Game()
    {
    }

    protected Game(string gameInput)
    {
        ListOfItems = new List<int>();
        _listOfItems = new List<int>(); 
        var gameParser = new GameParser();
        _listOfItems = gameParser.ParseGameInputString(gameInput);
    }

    public abstract int Bowl(int items);
}

    -

Updated based on the suggestions: Based on the suggestions below, here is the code I'm think to have in the final version:

public abstract class Game
{
    public IReadOnlyCollection<int> ListOfItems { get; } = new List<int>();

    protected Game()
    {
    }

    protected Game(string gameInput)
    {
        var gameParser = new GameParser();
        ListOfItems = gameParser.ParseGameInputString(gameInput);
    }

    public abstract int Bowl(int items);
}

You can just remove the setter : public List<int> ListOfItemss { get; } public List<int> ListOfItemss { get; }

Edit : As mentionned in the comments, you can get more infos about the difference between public List<int> ListOfItemss { get; } public List<int> ListOfItemss { get; } and public List<int> ListOfItemss { get; private set; } public List<int> ListOfItemss { get; private set; } public List<int> ListOfItemss { get; private set; } here

Remove the setter (which effectively makes it private to constructors). As Rufus has pointed out, if you don't want this list modifying outside the class, don't expose it as a list. Also, you allow the construction of a Game with a null ListOfItemss. I'd make that default constructor initialise the list, like the other c'tor does. This makes them consistent and avoids nasty null reference exceptions if you try to access game.ListOfItemss:

public abstract class Game
{
    public IEnumerable<int> ListOfItemss { get; } = new List<int>();

    protected Game()
    {
    }

    protected Game(string gameInput)
    {
        var gameParser = new GameParser();
        ListOfItemss = gameParser.ParseGameInputString(gameInput);
    }

    public abstract int Bowl(int items);
}

Frankly, you shouldn't be providing external access to that list at all, this violates encapsulation. Even though the property is declared IReadOnlyList<int> , there's nothing stopping someone from doing (List<int>)game.ListOfItemss . Private setter or not doesn't really matter, as long as you're limiting access to the internals. If you need to access items of your list externally, expose it through controlled methods such as an indexer.

class Option0
{
    private readonly List<int> items;
    public int this[int index] => this.items[index];
}

Only your class or perhaps derived classes should be allowed access to this list.

With that being said, if you want to expose it as a truly read only list, expose the read only view of it only.

class Option1
{
    private readonly List<int> items;
    public IReadOnlyList<int> Items => items.AsReadOnly();
    public Option1()
    {
        this.items = ...;
    }
}

class Option2
{
    private readonly List<int> items;
    public IReadOnlyList<int> Items { get; }
    public Option2()
    {
        this.items = ...;
        this.Items = this.items.AsReadOnly();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM