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

Thats my code. When running it I get object not set to an instance of an object at the line where I try to add student to a course. I need help explaining how to use interfaces as fields.

sirSemite
  • 3
  • 2
  • Specifically in this case you don't set value to either `Students` property (or backfield `students`), so it's `null` and `Students.Count()` will throw. – Sinatr Aug 03 '16 at 07:21

3 Answers3

4

With collection properties, it's a good practice to initialize them during construction, and expose them through a readonly getter:

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

This makes sure that the Students property is never null, and no code can replace the backing field with a different instance. This doesn't make the class immutable, however; you can still add and remove items from the Students collection.

With C#6 syntax you could also use an autoimplemented readonly property:

internal sealed class Course
{
    public ICollection<Student> Students { get; } = new List<Student>();
}
vgru
  • 49,838
  • 16
  • 120
  • 201
  • What if I don't want to use all the functionalities of the List, only add/remove/count? Do I have to make some custom class to inheret the ICollection ? – sirSemite Aug 03 '16 at 13:51
  • I would recommend using composition instead of inheritance in that case, i.e. make the `students` a private field, remove the public property completely, and expose only those public methods you need (which will operate on the private list). If you inherit from `ICollection`, you will have to implement all the methods in that interface yourself, but that's likely the wrong approach (*unless* you want a custom `StudentsCollection` which will fire events when the collection gets changed, but even then, a `Course` is not just a "collection of students"). – vgru Aug 03 '16 at 13:59
1

Your problem is not the interface, it's the fact that your not assigning anything to your variable.

private ICollection<Student> students;

this will fix it:

private ICollection<Student> students = new List<Student>();
kemiller2002
  • 113,795
  • 27
  • 197
  • 251
0

You need to create an actual instance of the property Students, for example using a constructor for the class Course:

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

An interface must be implemented by a real class.

Igor Damiani
  • 1,897
  • 9
  • 12