【问题标题】:How to add item to class list of objects populated in an IEnumerable [closed]如何将项目添加到 IEnumerable 中填充的对象的类列表中[关闭]
【发布时间】:2021-05-29 11:58:56
【问题描述】:

我有一个班级Team 喜欢

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);
    }
}

我怎样才能正确地创建一个方法来将玩家添加到团队类中,例如:

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

【问题讨论】:

  • 有什么问题?
  • 您为什么决定将Players 设为IEnumerable&lt;Player&gt; 类型?
  • 将类型从IEnumerable&lt;Player&gt;更改为IList&lt;Player&gt;ICollection&lt;Player&gt;
  • 快速提醒您问题中的乞求语气,Behseini (my recent feedback is in these comments)。在这种情况下,它让我注意到这个问题无论如何都是题外话。这个故事的寓意也许是倾听对你有帮助的建议。

标签: c#


【解决方案1】:

您不能在IEnumerable&lt;T&gt; 类型的对象中添加任何内容。原因是IEnumerable&lt;T&gt;essentially

公开枚举器,它支持对指定类型的集合进行简单迭代。

你需要的是一个集合。可能是List&lt;T&gt;

例如

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);
    }
}

注意:我还在构造函数中进行了一些检查,以便我们验证创建的对象是否处于一致状态(没有名称的团队,不会是团队)。

【讨论】:

    【解决方案2】:

    除非您确实需要公开(即从您的班级外部)设置的属性,否则不要将其公开。 IEnumerable&lt;T&gt; 是只读类型,不能向其添加元素。但是,您可以将元素添加到 List&lt;T&gt;

    将您的自动属性转换为具有支持字段的属性,然后访问您的类中的字段,但将该属性用于玩家的公开阅读:

    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);
        }
    }
    

    【讨论】:

    • @mjwills 你是对的。我将更新答案以使用具体的List&lt;T&gt;,因为无论如何它只是私下使用
    • 感谢@knittl,但我在构造函数Players = players; 上遇到错误,抱怨Players 是只读的!
    • @Behseini 哎呀,这是原始代码的剩余部分。您需要分配支持字段,而不是属性
    • 从技术上讲,将其公开为 IEnumerable 并不会使其只读。支持对象仍然是List,您可以按原样键入强制转换并以任何您想要的方式对其进行处理。如果您希望某些内容实际上是只读的,则需要使用 .AsReadOnly()
    【解决方案3】:

    您无法添加到Players,因为它是IEnumerable。只能添加特定种类的IEnumerable,例如列表和集合。这是您的代码可以破坏的一种方式:我(您班级的用户)可以将 Player 设置为您无法添加内容的 IEnumerable

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

    现在Player 是一个数组,当然不能添加!

    要允许向Players 添加内容,您需要选择允许添加的类型。例如,ICollection&lt;Player&gt;IList&lt;Player&gt;List&lt;Player&gt;

    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
    

    您可以创建一个这种类型的私有player 字段,如果需要,仍然可以公开IEnumerable&lt;Player&gt;。但是你需要删除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);
    }
    

    【讨论】:

      猜你喜欢
      • 2014-08-23
      • 1970-01-01
      • 1970-01-01
      • 2019-05-12
      • 1970-01-01
      • 1970-01-01
      • 2015-09-18
      • 2013-02-24
      • 1970-01-01
      相关资源
      最近更新 更多