Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List<T> is cleared problem

Tags:

c#

list

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?

like image 331
user366312 Avatar asked Oct 19 '09 13:10

user366312


People also ask

What does list Clear do?

Definition and Usage The clear() method removes all the elements from a list.

What does list Clear() function do C#?

Clear() methods are used to delete items of a List in C#. C# List class provides methods and properties to create a list of objects (classes). You can add items to a list during the initialization or using List. Add() and List.

How do I get the length of a list in C#?

Try this: Int32 length = yourList. Count; In C#, arrays have a Length property, anything implementing IList<T> (including List<T> ) will have a Count property.


2 Answers

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.

like image 198
Jon Skeet Avatar answered Oct 27 '22 00:10

Jon Skeet


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.

like image 34
Svish Avatar answered Oct 26 '22 23:10

Svish