Являются ли типы значений изменчивыми или неизменяемыми в C #? - PullRequest
14 голосов
/ 17 августа 2011

Поведение типов значений показывает, что любое значение, которое мы храним, не может быть изменено какой-либо другой переменной.

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

Ответы [ 3 ]

22 голосов
/ 17 августа 2011

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

Mutable:

public struct MutableValueType
{
    public int MyInt { get; set; }
}

Неизменное:

public struct ImmutableValueType
{
    private readonly int myInt;
    public ImmutableValueType(int i) { this.myInt = i; }

    public int MyInt { get { return this.myInt; } }
}

Встроенные типы значений (int, double и т. П.) являются неизменяемыми, но вы можете очень легко создать свой собственный изменяемый struct s.

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

SomeType t = new SomeType();
t.X = 5;

SomeType u = t;
t.X = 10;

Console.WriteLine(u.X);

Зависит от . Если SomeType является типом значения, он печатает 5, что является довольно запутанным результатом.

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

3 голосов
/ 17 августа 2011

все примитивные типы значений, такие как int, double, float, являются неизменяемыми. Но сами структуры являются изменяемыми. Поэтому необходимо принять меры, чтобы сделать их такими же неизменяемыми, поскольку это может привести к путанице.

1 голос
/ 15 марта 2012

Любой экземпляр типа значения, который содержит любую информацию, может быть преобразован в код, который может записать место хранения, в котором он содержится, и ни один экземпляр типа значения не может быть преобразован в код, который не может записать место хранения, в котором он содержится.Эти характеристики делают частные хранилища хранилищ изменяемых типов значений идеальными контейнерами данных во многих сценариях, поскольку они сочетают удобство обновления, вытекающее из изменчивости, с контролем, исходящим из неизменяемости.Обратите внимание, что можно написать код для типа значения таким образом, что невозможно изменить существующий экземпляр без предварительного наличия экземпляра (возможно, вновь созданного временного экземпляра), который содержит требуемые данные, и перезаписи содержимогопервый экземпляр с содержимым последнего, но это не сделает тип значения более или менее изменчивым, чем если бы не было такой возможности.Во многих случаях это просто служит для того, чтобы сделать мутацию неуклюжей и заставить ее выглядеть так, как если бы оператор вроде:

  MyKeyValuePair =
    new KeyValuePair<long,long>(MyKeyValuePair.Key+1, MyKeyValuePair.Value+1>;

создаст новый экземпляр, но оставит существующий экземпляр без изменений.Если бы KeyValuePair был неизменным классом, и один поток выполнял MyKeyValuePair.ToString(), в то время как другой поток выполнял вышеуказанный код, вызов ToString воздействовал бы либо на старый, либо на новый экземпляр и, таким образом, давал бы оба старых значения.или оба новых значения.Поскольку KeyValuePair является структурой, вышеприведенный оператор создаст новый экземпляр, но он не заставит MyKeyValuePair ссылаться на новый экземпляр - он просто будет использовать новый экземпляр в качестве шаблона, поля которого будут скопированыдо MyKeyValuePair.Если бы KeyValuePair была изменяемой структурой, наиболее естественное выражение вероятного предполагаемого значения для приведенного выше кода было бы больше похоже на:

  MyKeyValuePair.Key += 1;
  MyKeyValuePair.Value += 1;

или, возможно:

  var temp = MyKeyValuePair;
  MyKeyValuePair.Key = temp.Key+1;
  MyKeyValuePair.Value = temp.Value+1;

ипоследствия потоков были бы гораздо яснее.

...