Как создать неизменяемый класс?
-
20-08-2019 - |
Вопрос
Я работаю над созданием неизменяемого класса.
Я пометил все свойства как доступные только для чтения.
У меня есть список предметов в классе.
Хотя, если свойство доступно только для чтения, список можно изменить.
Открытие IEnumerable списка делает его неизменяемым.
Я хотел знать, каковы основные правила, которым нужно следовать, чтобы сделать класс неизменяемым?
Решение
Я думаю, ты на правильном пути -
- вся информация, введенная в класс, должна быть предоставлена в конструкторе
- все свойства должны быть только геттерами
- если коллекция (или массив) передается в конструктор, ее следует скопировать, чтобы вызывающая сторона не могла изменить ее позже.
- если вы собираетесь вернуть свою коллекцию, верните либо копию, либо версию, доступную только для чтения (например, используя ArrayList.ReadOnly или подобное — вы можете объединить это с предыдущим пунктом и магазин копия, доступная только для чтения, которая будет возвращена при доступе к ней вызывающей стороны), вернуть перечислитель или использовать какой-либо другой метод/свойство, которое обеспечивает доступ к коллекции только для чтения
- имейте в виду, что вы все равно можете выглядеть как изменяемый класс, если какой-либо из ваших членов является изменяемым - в этом случае вам следует скопировать любое состояние, которое вы хотите сохранить, и избегать возврата целых изменяемых объектов, если только вы не скопируете их. прежде чем вернуть их вызывающему абоненту - другой вариант - вернуть только неизменяемые "разделы" изменяемого объекта - спасибо @Brian Rasmussen за то, что он побудил меня расширить этот момент
Другие советы
Чтобы быть неизменяемыми, все ваши свойства и поля должны быть доступны только для чтения.И элементы любого списка сами по себе должны быть неизменяемыми.
Вы можете создать свойство списка только для чтения следующим образом:
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
}
Также имейте в виду, что:
public readonly object[] MyObjects;
не является неизменяемым, даже если он помечен ключевым словом readonly.Вы по-прежнему можете изменять отдельные ссылки/значения массива с помощью метода доступа к индексу.
Использовать 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; }
}
Другой вариант — использовать шаблон посетителя вместо того, чтобы вообще раскрывать какие-либо внутренние коллекции.