如何验证列表中的数据<>一个班级的财产?

时间:2013-10-09 12:22:01

标签: c# list oop properties

我刚刚学习OOP,我的练习有问题。我有一个有学生的SchoolClass。 SchoolClass中的学生不允许使用相同的编号。我有以下内容:

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

当我在Main()类中初始化两个具有相同编号的学生时,我有一个ArgumentException(“列表中的学生有相同的班级编号!”);正如所料。但是,当我有一个SchoolClass(s​​c)的实例并调用其学生列表并使用Add()(sc.students.Add(new Student(..))时,我可以插入一个重复编号的学生。同样是List.InsertAt()方法。我读到getter可以使用ReadOnlyCollection&lt; ...&gt;(...)或AsReadOnly()进行读取,但在这种情况下如何将新学生添加到列表中?

避免/解决此问题的最佳做法是什么?

6 个答案:

答案 0 :(得分:4)

您不应该公开列表&lt;&gt;你班上的财产 - 它几乎从来都不是一个好主意,因为它给了班级用户过多的数据控制权,在这种情况下肯定不是一个好的选择。相反,您应该只公开所需的属性,并执行自己的验证:

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

答案 1 :(得分:1)

我建议使用Dictionary,因为它非常适合根据Key来防止重复。它也比检查重复项时只使用List要快得多。

class SchoolClass
{
    protected Dictionary<uint, Student> _Students = new Dictionary<uint, Student>();
    public IEnumerable<Student> Students
    {
        get { return _Students.Values; }
    }

    public SchoolClass(List<Student> students)
    {
        if (students == null) throw new ArgumentNullException("Students list can not be null!");

        foreach (var student in students)
            AddStudent(student);
    }

    public void AddStudent(Student student)
    {
        if (_Students.ContainsKey(student.Number))
            throw new ArgumentException("There are students in the list with the same class number!");

        _Students.Add(student.Number, student);
    }
}

在示例中,我将Students公开为IEnumerable,因此很明显它无法直接修改,因为它没有AddRemove_StudentsDictionary用作此属性的支持者/来源。

我还展示了AddStudent方法,该方法将处理添加学生,并检查重复项Numbers


进一步澄清

_Studentsprotected,因此从SchoolClass派生的任何类都可以访问它。在这种情况下似乎很可能。

我没有为set { }定义Students,因为它是一个不应该直接修改的集合。不创建提供set使其成为唯一的修改方法是修改_Students(其支持者)。

答案 2 :(得分:0)

您可以将getter标记为readonly并编写以下方法以添加新学生

public void AddStudent(Student s)
{
    if(!this.studentList.Contains(s))
    this.studentList.Add(s);
    else
     throw new Exception("Duplicate entry");
}

Contains()仅在学生班级中有Equals Implemented时才有用。相反,您可以使用this.studentList.Any(s => s.Number == s.Number) @ pauls的评论,HashSet也是一个不错的选择...

答案 3 :(得分:0)

您可以使用System.Collections.ObjectModel.KeyedCollection:

public class SchoolClass : KeyedCollection<uint, Student>
    {
        protected override uint GetKeyForItem(Student newStudent)
        {
            return newStudent.Number;
        }
    }

当具有给定号码的学生已经存在时,这将抛出ArgumentException

答案 4 :(得分:0)

由于您使用getter中的列表instance.Property.Operation,因此您无需通过setter直接操作列表。只读属性可能不会为您提供所需的行为,因为只读属性只是没有setter的属性。

您实际上可以使用.AsReadOnly()方法,结合SchoolClass类的新方法,例如AddStudent(Student student)AddStudents(List<Students> students)AddStudents方法可以在循环中使用AddStudent方法,而这又可以在您的属性上使用私有的setter。验证可能会在私有设置器中完成。

请参阅http://msdn.microsoft.com/en-us/library/75e8y5dd.aspxhttp://msdn.microsoft.com/en-us/library/e78dcd75.aspx

答案 5 :(得分:0)

我认为您需要将List.Contains方法与自定义IEqualityComparer一起使用。因此,您可以与其他财产以及数字进行比较。因此,如果需要进行任何更改,您将无需更改代码即可提供。

请参阅this link