Как мне создать неизменный класс? - PullRequest
103 голосов
/ 09 декабря 2008

Я работаю над созданием неизменяемого класса.
Я пометил все свойства только для чтения.

У меня есть список предметов в классе.
Хотя, если свойство доступно только для чтения, список можно изменить.

Предоставление IEnumerable списка делает его неизменным.
Я хотел знать, каковы основные правила, которым нужно следовать, чтобы сделать класс неизменным?

Ответы [ 5 ]

113 голосов
/ 09 декабря 2008

Я думаю, что вы на правильном пути -

  • вся информация, введенная в класс, должна быть предоставлена ​​в конструкторе
  • все свойства должны быть только геттерами
  • если коллекция (или массив) передается в конструктор, ее следует скопировать, чтобы вызывающая сторона не смогла изменить ее позже
  • если вы собираетесь вернуть свою коллекцию, либо вернуть копию, либо версию только для чтения (например, используя ArrayList.ReadOnly или аналогичный - вы можете объединить это с предыдущим пунктом и хранить копию только для чтения, которая будет возвращена при обращении к ней вызывающих абонентов), возвращать перечислитель или использовать какой-либо другой метод / свойство, которое разрешает доступ только для чтения к коллекции
  • имейте в виду, что у вас все еще может появиться изменяемый класс, если какой-либо из ваших членов изменчив - в этом случае вам следует скопировать любое состояние, которое вы хотите сохранить, и избегать возврата целых изменяемых объектов, если только вы копируете их, прежде чем вернуть их вызывающей стороне - другой вариант - вернуть только неизменяемые «секции» изменяемого объекта - спасибо @Brian Rasmussen за то, что побудили меня расширить эту точку
17 голосов
/ 09 декабря 2008

Чтобы быть неизменным, все ваши свойства и поля должны быть доступны только для чтения. И предметы в любом списке должны быть сами по себе неизменными.

Вы можете создать свойство списка только для чтения следующим образом:

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

}
10 голосов
/ 09 декабря 2008

Также имейте в виду, что:

public readonly object[] MyObjects;

не является неизменным, даже если он помечен ключевым словом только для чтения. Вы по-прежнему можете изменять отдельные ссылки / значения массива по индексу доступа.

4 голосов
/ 09 декабря 2008

Используйте класс 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; }
}
1 голос
/ 09 декабря 2008

Другой вариант - использовать шаблон посетителя вместо того, чтобы вообще показывать какие-либо внутренние коллекции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...