如何验证类中 List<> 属性中的数据?

tti*_*tto 3 c# oop properties list

我现在正在学习面向对象编程,但我在练习中遇到了问题。我有一个有学生的学校班级。同一班级的学生人数不得相同。我有以下内容:

class SchoolClass 
{
    private List<Student> students;

    public List<Student> Students
    {
        get { return this.students; }
        set
        {
            if (value == null) throw new ArgumentNullException("Students list can not be null!");
            if (value.Select(n => n.Number).Distinct().Count() != value.Count())
                throw new ArgumentException("There are students in the list with the same class number!");
            this.students = value;
        }
    }
public SchoolClass( List<Student> students)
    {
        this.Students = students;
    }
}
class Student 
{
    private uint number;

    public uint Number
    {
        get { return this.number; }
        set
        {
            if (value == 0) throw new ArgumentException("Student's number can not be null!");
            else this.number = value;
        }
    }

    public Student(string name, uint number)
    {
        this.Number = number;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我在 Main() 类中初始化具有相同编号的两个学生时,出现 ArgumentException("列表中存在具有相同班级编号的学生!"); 正如预期的那样。但是,当我有一个 SchoolClass (sc) 实例并调用其学生列表并使用 Add() (sc.students.Add(new Student(..)) 时,我可以插入一个具有重复编号的学生。同样的情况List.InsertAt() 方法。我读到可以使用 ReadOnlyCollection<...>(...) 或 AsReadOnly() 来只读获取 getter,但是在这种情况下我将如何将新学生添加到列表中?

避免/解决此问题的最佳实践是什么?

sta*_*afl 5

您不应该在您的类上公开 List<> 属性 - 这几乎从来都不是一个好主意,因为它使类的用户对您的数据有太多的控制权,在这种情况下它当然不是一个好的选择。相反,您应该仅公开您需要的属性,并执行您自己的验证:

// store the students as a List<>...
private List<Student> students;

// ...but expose them as IEnumerable<>.
public IEnumerable<Student> Students
{
    get { return this.students; }
}

// IEnumerable<> does not allow adding, removing, clearing, etc - 
// you know you're the only one altering the data

// and you can choose to give them restricted access with your own
// validation logic
public void AddStudent(Student student) 
{
    if (this.students.Any(s => s.Number == student.Number))
        throw new ArgumentException("Duplicate student number!");
    this.students.Add(student);
}
Run Code Online (Sandbox Code Playgroud)