2016-08-03 43 views
0
namespace TestOOP 
{ 
    using System; 
    using System.Collections.Generic; 
    using System.Linq; 

    internal sealed class Student 
    { 
     private string name; 
    } 

    internal sealed class Course 
    { 
     private ICollection<Student> students; 

     public ICollection<Student> Students 
     { 
      get { return this.students; } 
      set { this.students = Students; } 
     } 
    } 

    class Program 
    { 
     static void Main() 
     { 
      var course = new Course(); 
      course.Students.Add(new Student()); 
      Console.WriteLine(course.Students.Count()); 
     } 
    } 
} 

那就是我的代码。在运行它时,我没有将对象设置为我尝试将学生添加到课程的对象的实例。我需要帮助解释如何使用接口作为字段。如何将界面用作字段?

+0

具体来说,在这种情况下,您不要将值设置为'学生'属性(或后场'学生'),所以它是'null'并且会抛出'Students.Count()'。 – Sinatr

回答

4

随着集合属性,这是一个很好的做法在施工期间进行初始化,并通过readonly吸气揭露他们:

internal sealed class Course 
{ 
    readonly List<Student> students = new List<Student>(); 
    public ICollection<Student> Students 
    { 
     get { return this.students; } 
    } 
} 

这可确保Students属性永远不会是空的,没有代码可以取代支持不同实例的字段。然而,这不会使这个类不可变,您仍然可以添加和删除Students集合中的项目。

用C#语法6,你也可以使用一个autoimplemented只读属性:

internal sealed class Course 
{ 
    public ICollection<Student> Students { get; } = new List<Student>(); 
} 
+0

如果我不想使用列表的所有功能,只添加/删除/计数会怎么样?我是否必须制作一些自定义类才能嵌入ICollection? – sirSemite

+0

在这种情况下,我会推荐使用组合而不是继承,即使学生成为私人领域,完全删除公共属性,并仅公开您需要的公共方法(这将在私人列表上运行)。如果你从'ICollection'继承,你将不得不在自己的接口中实现所有的方法,但这可能是错误的方法(*除非*你想要一个自定义的'StudentsCollection',当集合发生变化时会触发事件,那么,“课程”不仅仅是“学生的集合”)。 – Groo

1

你的问题不是接口,它是你不指定任何东西到你的变量的事实。

private ICollection<Student> students; 

这将解决它:

private ICollection<Student> students = new List<Student>(); 
0

您需要创建属性学生的实际情况下,例如使用该类课程构造:

internal sealed class Course 
{ 
    private ICollection<Student> students; 

    public ICollection<Student> Students 
    { 
     get { return this.students; } 
     set { this.students = Students; } 
    } 

    public Course() 
    { 
     this.Students = new List<Student>(); 
    } 
} 

接口必须由一个真正的班级来实施。