Истинное определение неизменности?

Мне интересно, как определяется неизменность? Если значения не выставляются как общедоступные, поэтому их нельзя изменить, то этого достаточно?

могут ли значения быть изменены внутри типа, а не клиентом типа?

или их можно установить только внутри конструктора? Если да, то в случаях двойной инициализации (с использованием this ключевое слово на структурах и т. д.) по-прежнему подходит для неизменяемых типов?

Как я могу гарантировать, что тип является 100% неизменяемым?

10 ответов


Если значения не выставляются как общедоступные, поэтому их нельзя изменить, то этого достаточно?

нет, потому что вам нужен доступ на чтение.

могут ли значения быть изменены внутри типа, а не клиентом типа?

нет, потому что это все-таки мутация.

или их можно установить только внутри конструктора?

Динь Динь Динь! С дополнительным моментом, что неизменяемые типы часто есть методы, которые строят и возвращают новые экземпляры, а также часто имеют дополнительные конструкторы, отмеченные internal специально для использования этих методов.

Как я могу гарантировать, что тип является 100% неизменяемым?

в .Net сложно получить такую гарантию, потому что вы можете использовать отражение для изменения (мутирования) частных членов.


предыдущие плакаты уже заявили, что вы должны назначить значения своим полям в конструкторе, а затем держать руки подальше от них. Но иногда это легче сказать, чем сделать. Предположим, что ваш неизменяемый объект предоставляет свойство типа List<string>. Этот список можно изменить? А если нет, то как вы будете контролировать это?

Эрик Липперт написал ряд сообщений в своем блоге о неизменности в C# , которые могут показаться вам интересными:вы найдете первый здесь.


одна вещь, которую я думаю, может быть упущена во всех этих ответах, заключается в том, что я думаю, что объект можно считать неизменным, даже если его внутреннее состояние изменяется - до тех пор, пока эти внутренние изменения не видны "клиентскому" коду.

например,System.String класс неизменяем, но я думаю, что было бы разрешено кэшировать хэш-код для экземпляра, поэтому хэш вычисляется только при первом вызове GetHashCode(). Обратите внимание, что насколько я знаю,System.String класс не сделайте это, но я думаю, что это можно и все еще считать неизменным. Конечно, любое из этих изменений должно быть обработано потокобезопасным способом (в соответствии с ненаблюдаемым аспектом изменений).

честно говоря, я не могу придумать много причин, по которым можно хотеть или нуждаться в этом типе "невидимой изменчивости".


вот определение неизменяемости из Википедии (ссылке)

"в объектно-ориентированном и функциональном программировании неизменяемым объектом является объект, состояние которого не может быть изменено после его создания."

по сути, после создания объекта ни одно из его свойств не может быть изменено. Примером является класс String. После создания объекта String его нельзя изменить. Любая операция, выполненная с ним, фактически создает новый объект String.


много вопросов. Я постараюсь ответить на каждый из них в отдельности:

  • " мне интересно, как определяется неизменность?"Прямо из Википедия страницы (и совершенно точная/краткое описание)

    неизменяемый объект-это объект, состояние которого не может быть изменен после его создания

  • " если значения не выставляются как общедоступные, поэтому не могут быть изменены, то этого достаточно?" - Не совсем. Он не может быть изменен в любым способом, так что вы должны убедиться, что методы/функции не изменяют состояние объекта, и при выполнении операций, всегда возвращают новый экземпляр.

  • " могут ли значения быть изменены внутри типа, а не клиентом типа?- ...Технически он не может быть изменен ни внутри, ни потребителем такого типа. На практике, такие типы, как System.String (ссылочный тип для этого вопроса) существуют, которые могут быть считается изменчивым почти для всех практических целей, хотя и не в теории.

  • "или можно установить только внутри конструктора?- ...Да, теоретически это только место, где можно установить состояние (переменные).

  • " если да, то в случаях двойной инициализации (с использованием ключевого слова this на структурах и т. д.) все еще нормально для неизменяемых типов?"- Да, это все еще прекрасно, потому что это все часть инициализации (создания) process, и экземпляр не возвращается, пока он не будет завершен.

  • " как я могу гарантировать, что тип является 100% неизменяемым?- ...Это должно быть обеспечено следующими условиями. (Кто-нибудь, пожалуйста, укажите, если я пропустил один.)

    1. Не раскрывайте никаких переменных. Все они должны быть private (даже не protected приемлемо, так как производные классы могут затем изменять состояние).
    2. Не позволяйте никаким методам экземпляра изменять состояние (переменные). Этот должно выполняться только в конструкторе, в то время как методы должны создавать новые экземпляры с использованием конкретного конструктора, если они требуют возврата "измененного" объекта.
    3. все члены, которые предоставляются (только для чтения) или объекты, возвращаемые методами должны быть неизменными.

    Примечание: Вы не можете гарантировать неизменность производных типов, поскольку они могут определять новые переменные. Это причина для маркировки любого типа, который вы не хотите, чтобы убедиться, что он неизменен как sealed Так что ни один производный класс не может считаться вашим базовым неизменяемым типом в любом месте кода.

надеюсь, что это поможет.


Я узнал, что неизменяемость-это когда вы устанавливаете все в конструкторе и не можете изменить его позже в течение жизни объекта.


определение неизменяемости может быть расположено на Google .

пример:

неизменяемый-буквально, не способный меняться.
www.filosofia.net/materiales/rec/glosaen.htm

с точки зрения неизменяемых структур данных типичным определением является write-once-read-many, другими словами, как вы говорите, после создания он не может быть изменен.

есть несколько случаев, которые находятся немного в серой области. Для например, строки .NET считаются неизменяемыми, поскольку они не могут изменяться, однако StringBuilder внутренне изменяет объект String.


неизменяемый-это, по сути, класс, который заставляет себя быть окончательным из своего собственного кода. Как только она есть, ничего нельзя изменить. Насколько мне известно, вещи устанавливаются в конструкторе,и все. Я не вижу, как что-то может быть неизменным в противном случае.


к сожалению, в c#/vb нет неизменяемых ключевых слов.net, хотя это обсуждалось, но если нет автопропертий, и все поля объявлены с помощью модфира readonly (поля readonly могут только делать ставки, назначенные в конструкторе), и что все поля объявлены неизменяемого типа, вы будете уверены в своей неизменности.


неизменяемым объектом является тот, чье наблюдаемое состояние никогда не может быть изменено какой-либо вероятной последовательностью выполнения кода. Неизменяемым типом является тот, который гарантирует, что любые экземпляры, открытые внешнему миру, будут неизменяемыми (это требование часто указывается как требующее, чтобы состояние объекта могло быть установлено только в его конструкторе; это не является строго необходимым в случае объектов с частными конструкторами и не является достаточным в случае объектов, которые вызывают внешние методы на сами во время строительства).

точка, которой другие ответы пренебрегли, однако, является определением состояния объекта. Если Foo - Это класс, состояние List<Foo> состоит из последовательности объект удостоверения содержащиеся в нем. Если только ссылка на конкретный List<Foo> экземпляр удерживается кодом, который не будет ни изменять эту последовательность, ни подвергать ее воздействию кода, который может это сделать, тогда этот экземпляр будет неизменяемым, независимо от того, the Foo объекты, указанные в нем являются изменяемыми или неизменяемыми.

чтобы использовать аналогию, если у вас есть список автомобильных VINs (идентификационных номеров транспортных средств), напечатанных на бумаге, очевидной для подделки, сам список будет неизменным, даже если автомобили не являются. Даже если список содержит десять красных автомобилей сегодня, он может содержать десять синих автомобилей завтра;они все равно будут теми же десятью автомобилями.