Неизменяемость по-прежнему остается областью, где C # созревает. До сих пор C # не принял семантику const
C ++ ... что, на самом деле, я считаю хорошей вещью. Поведение const
в C ++ часто затрудняло проектирование иерархий классов, которые работали бы так, как вы хотели. Нередко можно было увидеть код с const_cast<>
для обхода константности там, где это было нежелательно. Надеемся, что разработчики C # придумают более простую, но все же выразительную альтернативу.
В настоящее время не существует языковой функции, которая помечает параметры или объекты, передаваемые в методы, как неизменяемые. Лучшее, что вы можете сделать, - передать объект, используя интерфейс (или, что еще лучше, оболочку), который только разрешает операции чтения.
Для некоторых стандартных коллекций в .NET вы можете использовать оболочку ReadOnlyCollection
, которая инкапсулирует любой изменяемый тип ICollection
в контейнере только для чтения.
Создание неизменяемых типов требует планирования и понимания языковых особенностей. Например, ключевое слово readonly
- ваш друг. Это позволяет вам объявить членов класса или структуры неизменяемыми. К сожалению, эта неизменность применяется только к ссылке, а не к элементам ссылочного объекта. Это означает, что вы можете объявить:
private readonly int[] m_Values = new int[100];
public void SomeMethod()
{
m_Values = new int[50]; // illegal, won't compile!
m_Values[10] = 42; // perfectly legal, yet undesirable
}
В приведенном выше примере ссылка на массив является неизменной, но отдельные элементы массива - нет. Это поведение выходит за рамки массивов, конечно.
Практика, которую я нашел полезной при разработке неизменяемых типов, заключается в разделении неизменяемого поведения на собственный интерфейс , который затем реализуется классом, который управляет данными. Интерфейс предоставляет только те свойства и методы get, которые гарантированно не изменяют состояние объекта. Затем можно передавать экземпляры вашего типа в методы в качестве параметров этого типа интерфейса. Это слабая форма поддержки неизменяемости - поскольку вызываемый метод часто может приводить ссылку на изменяемый тип . Лучшей, но более громоздкой альтернативой является создание реализации-оболочки, которая реализует тот же интерфейс и поддерживает ссылку на фактический экземпляр (так же, как ReadOnlyCollection
). Это больше работы, но дает более сильную гарантию неизменности.
Подход, который вы выбираете, зависит от того, насколько важны гарантии неизменности и сколько времени и усилий вы готовы потратить, чтобы туда добраться.
Если вам интересно больше узнать эту тему, у Эрика Липперта есть отличная серия статей об неизменяемости в C # .