1

I have a class Team like

public class Team
{
    public string Name { get; set; } = string.Empty;
    public IEnumerable<Player> Players { get; set; } = new List<Player>();
    
    public Team(string name, IEnumerable<Player> players)
    {
        Name = name;
        Players = players;
    }
    
    public void addPlayer(Player pl){
     // Players.Add(pl);
    }
}

How can I properly create a method to add a player to the team class like:

 public void addPlayer(Player pl){
     // Players.Add(pl);
    }
halfer
  • 19,824
  • 17
  • 99
  • 186
Behseini
  • 6,066
  • 23
  • 78
  • 125
  • what is the issue? – Vivek Nuna Feb 27 '21 at 08:55
  • 2
    Why did you decide to make `Players` to be of type `IEnumerable`? – Sweeper Feb 27 '21 at 08:55
  • Change the type from `IEnumerable` to `IList` or `ICollection`. – Progman Feb 27 '21 at 08:55
  • 1
    Does this answer your question? [How can I add an item to a IEnumerable collection?](https://stackoverflow.com/questions/1210295/how-can-i-add-an-item-to-a-ienumerablet-collection) – d219 Feb 27 '21 at 09:26
  • A quick reminder about the begging tone in your questions, Behseini ([my recent feedback is in these comments](https://stackoverflow.com/questions/66293794/how-to-navigate-to-cpt-archive-from-listed-taxonomy-term#comment117239926_66293794)). On this occasion, it drew my attention to the fact that the question is off-topic anyway. The moral of the story is perhaps to listen to advice that will help you. – halfer Feb 27 '21 at 20:00

3 Answers3

2

Unless you really need a property to be publically (i.e. from the outside of your class) settable, don't make it public. An IEnumerable<T> is a read-only type, you cannot add elements to it. However, you can add elements to a List<T>.

Convert your auto-property to a property with a backing field and then access the field inside your class, but use the property for public reading of the players:

public class Team
{
    private readonly List<Player> players;

    public string Name { get; }
    public IEnumerable<Player> Players => this.players;
    // older versions of C#: Players { get { return this.players; } }
    
    public Team(string name, List<Player> players)
    {
        this.Name = name;
        this.players = players;
    }
    
    public void addPlayer(Player pl) {
        this.players.Add(pl);
    }
}
knittl
  • 246,190
  • 53
  • 318
  • 364
  • @mjwills you are right. I'll update the answer to use a concrete `List`, since it is only used privately anyway – knittl Feb 27 '21 at 09:16
  • thanks @knittl but I am getting error on constructor `Players = players;` complaining that the `Players` is read only! – Behseini Feb 27 '21 at 09:25
  • @Behseini whoops, that was a leftover from the original code. You need to assign the backing field, not the property – knittl Feb 27 '21 at 09:30
  • 1
    Technically, exposing it as an `IEnumerable` doesn't make it read only. The backing object is still a `List` and you can type cast it as such and mess with it any way you want. If you want something to be actually read only you need to use `.AsReadOnly()`. – Bradford Dillon Feb 28 '21 at 04:48
2

You can't add to Players because it is an IEnumerable. Only specific kinds of IEnumerable, such as lists and sets, can be added to. Here's one way your code can break: I (a user of your class) can set Player to an IEnumerable that you can't add things to:

var team = new Team("My Team", new Player[] { });
team.AddPlayer(new Player(...));

Now Player is an array, which you certainly can't add to!

To allow adding things to Players, you need to choose an type that allows adding. For example, an ICollection<Player>, IList<Player>, or List<Player>.

public ICollection<Player> Players { get; set; }
public Team(string name, IEnumerable<Player> players)
    Name = name;
    Players = players.ToList();
}

// uncommenting the line in AddPlayer will now compile

You can make a private player field of this type, and still expose a IEnumerable<Player> if you want. But you need to remove the setter:

private List<Player> players;
public IEnumerable<Player> Players => players;
public Team(string name, IEnumerable<Player> players)
    Name = name;
    this.players = players.ToList();
}

public void addPlayer(Player pl){
    players.Add(pl);
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313
1

You can't add anything in an object of type IEnumerable<T>. The reason is that IEnumerable<T> essentially.

Exposes the enumerator, which supports a simple iteration over a collection of a specified type.

That you need is a Collection. Possibly a List<T>.

E.g.

public class Team
{
    // Make essentially readonly these properties
    public string Name { get; }
    public List<Player> Players { get; }

    public Team(string name, List<Player> players)
    {
        if(String.IsNullOrWhiteSpace(name))
        {
            throw new ArgumentException($"{nameof(name)} cannot be null or empty");
        }
        Name = name;
    
        Players = player ?? throw new ArgumentNullException(nameof(players));
    }

    public void addPlayer(Player pl)
    {
        Players.Add(pl);
    }
}

Note: that I have placed also some checks in the constructor, in order we verify that the object is created is in a consistent state (a team without a name, wouldn't be a team).

Christos
  • 53,228
  • 8
  • 76
  • 108