简体   繁体   English

类设计-属性默认值

[英]Class design - properties default value

Just wondering what the recommended way of tackling this scenario is and why it's better one way or another. 只是想知道解决这种情况的推荐方法是什么,以及为什么一种或另一种更好。

Let's say you have a class that represents a football team, you probably have something similar to this (oversimplified version of course): 假设您有一个代表足球队的班级,可能与此类似(当然是过分简化的版本):

public class FootballTeam
{
    public FootballTeam(string name, Person owner)
    {
        Name = name;
        Owner = owner;
    }

    public string Name {get;}

    public Person Trainer {get; set;}

    public Person Owner {get; set;}

    public List<Person> Roster {get; set;}
}

Now, we could argue that even a team with no players still has a roster, only it's an empty roster (as oppose to a non-existing roster). 现在,我们可以争辩说,即使是没有球员的球队也有名册,只是一个空的名册(与不存在的名册相对)。

So it would maybe make more sense to declare the Roster like this: 因此,这样声明Roster可能更有意义:

public List<Person> Roster {get; set;} = new List<Person>();

But this still suffers from a problem in my opinion: 但是我认为这仍然存在一个问题:

Because Roster still has a setter, it does nothing to prevent it from being set to null , which also makes it easy to wrongly assume that it can never be null . 因为Roster仍然有一个setter,所以它不会做任何事情来防止将其设置为null ,这也很容易错误地假定它永远不会为null

So instead Roster should look like this: 因此, Roster应如下所示:

public List<Person> Roster {get;} = new List<Person>();

So now we're semantically correct in the sense that a team always has a roster, only sometimes the roster contains no players. 因此,从某种意义上说,从某种意义上说,从某种意义上说,团队一直都有名册,只是有时名册上没有任何球员。 And we simplify things for the caller in the sense that they don't have to worry about null references. 而且我们从某种意义上简化了调用方的事情,因为他们不必担心空引用。

But in doing so we lost the ability to easily replace the complete existing roster with another one we already had, we're bound to that instance which we have to add/remove/clear Persons from, if we have two teams with the same players checking their Rosters for equality will return false , etc. 但是这样做的话,我们失去了用现有的另一名球员轻松替换现有全部球员的能力,如果我们有两支拥有相同球员的球队,那么我们就不得不添加/删除/清除Persons 。检查其Rosters是否相等将返回false等。

So a couple of questions: 有几个问题:

  1. What would be the best way to tackle this? 解决这个问题的最佳方法是什么? Hiding the List<Person> and presenting forwarding methods to indirectly interact with it seems overkill and of little added bonus. 隐藏List<Person>并提出间接与之交互的转发方法似乎是过分的,几乎没有任何好处。 Removing the setter removes some simplicity and functionality, allowing the Roster to be null seems even worse to me. 删除设置器会删除一些简单性和功能,对我而言,允许Rosternull似乎更糟。

  2. Assuming that the answer to 1. involves assigning a default value to the Roster property, are there any best practices as to where to do this? 假设1.的答案涉及为Roster属性分配一个默认值,那么在哪里执行此操作是否有最佳实践? ie, directly at the property like on the examples above or on the constructor? 即直接在上面的示例或构造函数上的属性上?

  3. You could also argue that a team must always have an Owner as well, although it does not necessarily need to always have a Trainer . 您也可能会争辩说,团队也必须始终拥有一个Owner ,尽管不一定需要始终拥有一个Trainer How would you handle this as well? 您将如何处理呢? Forwarding methods or checking if value == null on the setter and if so throw ? 转发方法或检查setter上的value == null是否throw

If team "owns" the list, I would expect to see something like this: 如果团队“拥有”该列表,那么我希望看到以下内容:

public class FootballTeam
{
    private readonly List<Person> _roster = new List<Person>();
    public FootballTeam(string name, Person owner)
    {
        Name = name;
        Owner = owner;
    }

    public string Name {get;}

    public Person Trainer {get; set;}

    public Person Owner {get; set;}

    public IEnumerable<Person> Roster => _roster.AsReadOnly();

    public void AddPlayer(Person player) {
       _roster.Add(player);
       //Other logic
    }

    public void RemovePlayer(Person player) {
       //What if the player isn't on our roster?
       //Other logic?
       _roster.Remove(player);
    }

    public void ReplaceRoster(IEnumerable<Person> players) {
       _roster.Clear();
       _roster.AddRange(players);
    }
}

I wouldn't normally have added the ReplaceRoster method but apparently that's one of your use cases. 我通常不会添加ReplaceRoster方法,但是显然这是您的用例之一。 Note the fact that we're using a List is now encapsulated and we've moved up a semantic level in the methods that our class supports. 请注意,我们现在已经封装了使用List的事实,并且在类支持的方法中提高了语义级别。

Other methods within our class can rely on _roster being non-null. 我们类中的其他方法可以依靠_roster为非null。 Consumers of our class can always rely on getting the IEnumerable<Person> even when the roster is empty. 我们的类的消费者始终可以依赖于获取IEnumerable<Person>即使名册为空。

If the team doesn't "own" the list, I wouldn't expect it to have the property at all. 如果团队不“拥有”列表,那么我根本就不会拥有该属性。

Try this: 尝试这个:

private List<Person> _roster = new List<Person>();
public List<Person> Roster {get=>_roster; set=>_roster = value ?? new List<Person>();}

This will prevent from assigning null to _roster. 这将防止为_roster分配null。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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