Неизменяемость - это область, в которой C # все еще нуждается в улучшении. Хотя создание простых неизменяемых типов со свойствами readonly
возможно, если вам требуется более сложный контроль над изменяемым типом, вы начинаете сталкиваться с препятствиями. .
У вас есть три варианта, в зависимости от того, насколько сильно вам нужно «применять» поведение только для чтения:
Используйте флаг «только для чтения» в своем типе (как вы делаете), и пусть вызывающая сторона будет ответственна за то, что она не пытается изменить свойства типа - если сделана попытка записи, бросьте исключение.
Создайте интерфейс только для чтения и используйте его для своего типа. Таким образом, вы можете передать тип через этот интерфейс к коду, который должен выполнять только чтение.
Создайте класс-оболочку, который агрегирует ваш тип и предоставляет только операции чтения.
Первый вариант часто является самым простым, поскольку он может потребовать меньшего количества рефакторинга существующего кода, но предлагает наименьшую возможность автору типа информировать потребителей, когда экземпляр является неизменяемым, а когда нет. Эта опция также предлагает наименьшую поддержку от компилятора при обнаружении несоответствующего использования - и переводит обнаружение ошибок во время выполнения.
Второй вариант удобен, так как реализация интерфейса возможна без особых усилий по рефакторингу. К сожалению, вызывающие все еще могут приводить к базовому типу и пытаться писать против него. Часто эта опция сочетается с флагом только для чтения, чтобы гарантировать, что неизменность не нарушена.
Третий вариант является самым сильным с точки зрения принудительного применения, но он может привести к дублированию кода и требует больше усилий по рефакторингу. Часто полезно комбинировать опции 2 и 3, чтобы сделать связь между оболочкой, доступной только для чтения, и изменяемым типом полиморфной.
Лично я склоняюсь к третьему варианту при написании нового кода, в котором, как я ожидаю, потребуется обеспечить неизменность. Мне нравится тот факт, что невозможно «отбросить» неизменяемую оболочку, и она часто позволяет избежать записи грязных проверок if-only-only-throw-exception в каждый сеттер.