Что означает неизменяемый и только для чтения в C #? - PullRequest
14 голосов
/ 27 июля 2011

Правильно ли, что невозможно изменить значение неизменяемого объекта?

У меня есть два сценария относительно readonly, которые я хочу понять:

  1. Что делать, если у меня есть коллекция и пометить ее как readonly, как показано ниже.Могу ли я позвонить _items.Add?

    private readonly ICollection<MyItem> _items;
    
  2. А также для следующей переменной, если позже я вызову _metadata.Change, которая изменит внутренние значения переменной-члена пары в экземпляре Metadata._metadata по-прежнему неизменен?

    private readonly Metadata _metadata;
    

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

Ответы [ 8 ]

23 голосов
/ 27 июля 2011

Предлагаю вам прочитать серию постов Эрика Липперта в блоге.Первая часть - Неизменяемость в C # Часть первая: Виды неизменности .Очень информативно и полезно, как всегда.В этой серии подробно описывается, что означает для переменной только для чтения , неизменной и т. Д.переназначить поле вне конструктора.Само поле может быть изменено до тех пор, пока оно остается в том же экземпляре.Так что да, вы можете добавлять элементы в коллекцию, хранящуюся в поле readonly.

Что касается изменчивости, это более сложный вопрос, и он немного зависит от того, какой вид изменчивости вы считаете.Когда внутренние значения Metadata являются ссылками, а сами эти ссылки (на экземпляры, на которые они указывают) не изменяются, можно сказать, что Metadata остается неизменным.Но он мутировал логически .Смотрите сообщения Эрика для более глубокого понимания.

7 голосов
/ 27 июля 2011

Пометка поля как доступного только для чтения означает, что вы не можете изменить значение этого поля.Это не имеет никакого отношения к внутреннему состоянию объекта там.В ваших примерах, хотя вы не сможете назначить новый объект метаданных в поле _metadata или новую ICollection в поле _items (вне конструктора), вы можете изменить внутренние значения существующих объектов, хранящихся вэти поля.

5 голосов
/ 27 июля 2011

неизменный объект - это объект, который нельзя изменить после его создания. В C # строки неизменны. Если вы посмотрите на процедуры манипуляции со строками, то увидите, что все они возвращают новую измененную строку и оставляют исходную строку без изменений.

Это значительно облегчает обработку строк. Если у вас есть ссылка на строку, вы можете быть уверены, что никто другой неожиданно не изменит ее под вашими ногами.

readonly это что-то еще. Это означает, что ссылка не может быть изменена после установки и может быть установлена ​​только во время строительства объекта. В ваших примерах вы можете изменить содержимое _items или свойства _metadata, но нельзя назначить другой ICollection<MyItem> элементу _items или другой экземпляр Metadata на _metadata.

readonly устанавливается на ссылку на объект. Неизменность - это свойство самого объекта. Их можно свободно комбинировать. Чтобы свойство никоим образом не изменялось, оно должно быть ссылкой только для чтения на неизменяемый объект.

3 голосов
/ 27 июля 2011

private readonly ICollection<MyItem> _items;

Не препятствует добавлению элементов. Это просто предотвращает повторное назначение _items. То же самое верно для _metadata. Доступные члены _metadata могут быть изменены - _metadata не может быть переназначен.

3 голосов
/ 27 июля 2011

Ничто не мешает вам изменить объект, хранящийся в поле readonly. Таким образом, вы можете вызвать _items.Add() и metadata._Change() вне конструктора / инициализатора. readonly только запрещает вам присваивать новые значения этим полям после создания.

2 голосов
/ 27 июля 2011

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

2 голосов
/ 27 июля 2011
  1. Да.
  2. Readonly не равно неизменному. Вы все еще можете вызвать _metadata.Change.
0 голосов
/ 15 февраля 2016

В таких языках, как C ++, существует довольно много разных вариантов использования ключевого слова "const", разработчикам частично легко передавать постоянные параметры, а также постоянные указатели постоянных значений.

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

В Java немного проще, чем в C # из-за ключевого слова final и его использования.

Давайте рассмотрим этот пример и посмотрим, насколько он неизменен ..

public sealed class ImmutableFoo
    {
        private ImmutableFoo()
        {

        }

        public string SomeValue { get; private set; }
        //more properties go here

        public sealed class Builder
        {
            private readonly ImmutableFoo _instanceFoo = new ImmutableFoo();
            public Builder SetSomeValue(string someValue)
            {
                _instanceFoo.SomeValue = someValue;
                return this;
            }

            /// Set more properties go here
            /// 

            public ImmutableFoo Build()
            {
                return _instanceFoo;
            }
        }
    }

Вы можете использовать это так

public class Program
    {
        public static void Main(string[] args)
        {
            ImmutableFoo foo = new ImmutableFoo.Builder()
                .SetSomeValue("Assil is my name")
                .Build();

            Console.WriteLine(foo.SomeValue);
            Console.WriteLine("Hit enter to terminate");
            Console.ReadLine();
        }
    }
...