Пункт 1 - Храните ссылки в вашем списке
С точки зрения API, объект никогда не должен давать ссылку на свой внутренний список. Это связано с проблемой, которую вы только что обнаружили, из-за которой другой потребительский код может изменить этот список так, как он считает нужным. Каждая ссылка в этом списке, как обмениваемая, включая объект-владелец, обновляет свой список. Обычно это не то, что было задумано.
Кроме того, потребитель не несет ответственности за создание собственной копии. Ответственность за сохранение приватности его версии лежит на владельце списка.
Создать новый список достаточно просто
private List<Gene> initialGeneList;
public List<Gene> InitialGenes
{
get { return new List<Gene>(initialGeneList); } // return a new list
}
Этот совет также включает передачу вашего собственного списка другому классу / методу.
Пункт 2 - рассмотрите возможность использования неизменного объекта
Не вдаваясь слишком в ссылки на типы значений, это означает, что объект обрабатывается как тип значения, и всякий раз, когда у вас есть операция, вместо изменения оригинала возвращается новый объект.
Типы реальных значений в .net, такие как целые числа и DateTimes, имеют семантику копирования при присваивании. например При назначении копия создается.
Ссылочные типы также могут вести себя как типы значений, и строки являются хорошим примером. Многие люди делают следующую ошибку, потому что они не понимают семантику типа значения System.String.
string s = "Hello World";
s.Substring(0,5); // s unchanged. still 'Hello World'
s = s.Substring(0,5); // s changed. now 'Hello'
Строковый метод Substring()
не изменяет исходный объект, а вместо этого возвращает новый, содержащий результат операции.
Где это уместно, использование неизменяемых объектов может значительно облегчить понимание программы и значительно уменьшить количество дефектов.
При реализации неизменяемых объектов одна оговорка, вероятно, необходима для реализации равенства значений для сравнения двух объектов (путем переопределения Equals
). Объекты являются ссылочными типами, и по умолчанию два объекта равны, если их ссылки равны.
В этом фрагменте значения объектов равны, но это разные объекты.
string s1 = "Hello";
string s2 = string.Concat("He","l", "lo");
bool equal = s1.Equals(s2);
bool referenceEqual = object.ReferenceEquals(s1, s2);
// s1 == s2 => True, Reference Equal => False
Console.Write("s1 == s2 => {0}, Reference Equal => {1}", equal, referenceEqual);