Как создать неизменяемый класс?
Я работаю над созданием неизменяемого класса.
Я пометил все свойства как доступные только для чтения.
У меня есть список элементов в классе.
Хотя если свойство доступно только для чтения, список может быть изменен.
Воздействие IEnumerable в списке делает его неизменным.
Я хотел знать, каковы основные правила, которые нужно соблюдать, чтобы сделать класс неизменным?
Ответы
Ответ 1
Я думаю, что ты на правильном пути -
- вся информация, введенная в класс, должна быть указана в конструкторе
- все свойства должны быть только для геттеров
- если коллекция (или массив) передается в конструктор, она должна быть скопирована, чтобы запретить ее модификатору позже
- если вы собираетесь вернуть свою коллекцию, верните копию или версию для чтения (например, используя ArrayList.ReadOnly или аналогичный - вы можете объединить это с предыдущей точкой и сохранить копию только для чтения, которая будет возвращена, когда вызывающие абоненты обратятся к ней), вернуть перечислитель или использовать другой метод/свойство, позволяющий доступ только для чтения в коллекцию
- Имейте в виду, что вы все еще можете иметь вид изменяемого класса, если какой-либо из ваших членов изменен - если это так, вы должны скопировать все состояние, которое вы хотите сохранить, и не возвращать все изменяемые объекты, кроме вы копируете их, прежде чем возвращать их вызывающему абоненту. Другой вариант - вернуть только неизменные "разделы" изменяемого объекта - благодаря @Brian Расмуссену, чтобы побудить меня расширить эту точку.
Ответ 2
Чтобы быть неизменными, все ваши свойства и поля должны быть только для чтения. И элементы в любом списке сами должны быть неизменными.
Вы можете сделать свойство списка только для чтения следующим образом:
public class MyClass
{
public MyClass(..., IList<MyType> items)
{
...
_myReadOnlyList = new List<MyType>(items).AsReadOnly();
}
public IList<MyType> MyReadOnlyList
{
get { return _myReadOnlyList; }
}
private IList<MyType> _myReadOnlyList
}
Ответ 3
Кроме того, имейте в виду, что:
public readonly object[] MyObjects;
не является неизменным, даже если он имеет ключевое слово readonly. Вы по-прежнему можете изменять отдельные ссылки/значения массивов с помощью индексного доступа.
Ответ 4
Используйте класс ReadOnlyCollection
. Он расположен в пространстве имен System.Collections.ObjectModel
.
Во всем, что возвращает ваш список (или в конструкторе), установите этот список как коллекцию только для чтения.
using System.Collections.ObjectModel;
...
public MyClass(..., List<ListItemType> theList, ...)
{
...
this.myListItemCollection= theList.AsReadOnly();
...
}
public ReadOnlyCollection<ListItemType> ListItems
{
get { return this.myListItemCollection; }
}
Ответ 5
Другой вариант - использовать шаблон посетителя вместо того, чтобы публиковать любые внутренние коллекции.