2009-10-19 10 views
6

Proszę spojrzeć na kod. Nie powinno zająć dużo czasu, aby rzucić okiem.Lista <T> jest wyczyszczona problem

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

Od GetCourse() zwraca referencję _items, nazywając t.GetCourses().Clear(); jest wyczyszczenie stanowiącego podstawę Course -list w instancji Teacher.

Chcę temu zapobiec. Oznacza to, że GetCourse() zwróci listę, ale nie można jej modyfikować.

Jak to osiągnąć?

Odpowiedz

15

Można utworzyć kopię listy, lub owinąć go w ReadOnlyCollection:

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

lub

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

Pierwsza opcja tworzy niezależną list - rozmówca będzie mógł go modyfikować , dodawanie lub usuwanie elementów, ale zmiany te nie będą widoczne na liście obiektów nauczyciela. Druga opcja to tylko opakowanie wokół istniejącej listy - więc wszelkie zmiany w kolekcji będą widoczne za pomocą opakowania. Osoba dzwoniąca nie będzie mogła dokonać żadnych zmian w kolekcji.

Należy pamiętać, że w obu przypadkach, jeśli obiekty wymienione na liście mają zmienione dane, zmiany te będą widoczne w obu kierunkach - trzeba by było sklonować każdy kod Course, jeśli chce się to zatrzymać.

+0

Czy tak się teraz robi w języku C#? Jestem poza pętlą C#, ale czy mógłbyś utworzyć nową Listę w ten sposób, czy też w jakiś sposób sklonowałbyś listę? Podejrzewam, że Lista zawiera metodę dokładnego kopiowania listy. –

+2

@Thomas: Nie sądzę, że jest coś w 'List ', aby utworzyć głęboki klon. Klonowanie jest w dużym stopniu zniechęcone moim doświadczeniem. –

5

Zamiast tego zwracasz numer IEnumerable<Course>?

Lekko off topic: Jeśli naprawdę chcesz, aby powrócić do listy, które mogą być dodawane do wyczyszczone, et cetera, powinieneś zwrócić Collection<T> zamiast List<T>, a może nawet jeden z interfejsów, na przykład ICollection<T>. Ogólnie rzecz biorąc powiedziałbym, że powinieneś zawsze zwracać najbardziej restrykcyjny typ, ponieważ łatwiej jest poluzować takie rzeczy, niż je zawęzić później.

+0

Dzwoniący może odesłać go do listy i nadal modyfikować listę podstawową. –