简体   繁体   中英

List<T> is cleared problem

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?

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.

How about returning an IEnumerable<Course> instead?

Slightly off topic: If you really do want to return a list that can be added to, cleared, et cetera, you should probably return a Collection<T> instead of a List<T> , or maybe even one of the interfaces, for example ICollection<T> . In general I would say you should always return the most restrictive type that you can, since it is easier to loosen up things like that than to narrow it down later.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM