tags:

views:

164

answers:

2

Please take a look at the code. It shouldn't take long to have a glimpse.

class Teacher
    {
        private int _id;
        public int ID
        {
            get { return _id; }
            set { _id = value; }
        }

        private string _message;
        public string Message
        {
            get { return _message; }
            set { _message = value; }
        }

        public Teacher(int id, string msg)
        {
            _id = id;
            _message = msg;
        }

        private List<Course> _items;
        public List<Course> GetCourses()
        {
            return _items;
        }

        public Teacher()
        {
            if (_items == null)
            {
                _items = new List<Course>();
            }

            _items.Add(new Course(1, "cpp"));
            _items.Add(new Course(1, "java"));
            _items.Add(new Course(1, "cs"));
        }

        public void Show()
        {
            Console.WriteLine(this._id);
            Console.WriteLine(this._message);
        }

        public void ShowList()
        {
            foreach(Course c in _items)
            {
                c.Show();
            }
        }
    }

    class Course
    {
        private int _id;
        public int ID
        {
            get { return _id; }
            set { _id = value; }
        }

        private string _message;
        public string Message
        {
            get { return _message; }
            set { _message = value; }
        }

        public Course(int id, string msg)
        {
            _id = id;
            _message = msg;
        }

        private List<Teacher> _items;
        public List<Teacher> GetTeachers()
        {
            return _items;
        }

        public Course()
        {
            if(_items == null)
            {
                _items = new List<Teacher>();
            }

            _items.Add(new Teacher(1, "ttt"));
            _items.Add(new Teacher(1, "ppp"));
            _items.Add(new Teacher(1, "mmm"));
        }

        public void Show()
        {
            Console.WriteLine(this._id);
            Console.WriteLine(this._message);
        }

        public void ShowList()
        {
            foreach (Teacher t in _items)
            {
                t.Show();
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Teacher t = new Teacher();
            t.ID = 1;
            t.Message = "Damn";

            t.Show();
            t.ShowList();

            t.GetCourses().Clear();

            t.Show();
            t.ShowList();

            Console.ReadLine();
        }
    }

Since GetCourse() returns a reference of _items, calling t.GetCourses().Clear(); is clearing the underlying Course-list in the Teacher instance.

I want to prevent this behaviour. That is, the GetCourse() would return a list but it would not be modifiable.

How to achieve that?

+15  A: 

You could create a copy of the list, or wrap it in ReadOnlyCollection:

private List<Course> _items;
public IList<Course> GetCourses()
{
    return new List<Course>(_items);
}

or

private List<Course> _items;
public IList<Course> GetCourses()
{
    return new ReadOnlyCollection<Course>(_items);
}

The first option creates an independent list - the caller will be able to modify it, adding or removing items, but those changes won't be seen in the teacher object's list. The second option is just a wrapper around the existing list - so any changes to the collection will be visible through the wrapper. The caller won't be able to make any changes to the collection.

Note that in both cases, if the Course objects referenced by the list have their data changed, those changes will be visible either way - you'd have to clone each Course if you want to stop that happening.

Jon Skeet
Is this how it's done in C# now? I'm out of the C# loop, but would you make a new List like that or would you somehow clone the list? I would suspect that the List contains a method to deep-copy the list.
Thomas Owens
@Thomas: I don't think there's anything in `List<T>` to create a deep clone. Cloning is largely discouraged in my experience.
Jon Skeet
+5  A: 
Svish
A caller could cast that back to List<Course> and still modify the underlying list.
Peter van der Heijden