В С#, являются ли типы значений изменчивыми или неизменяемыми?
Поведение типов значений показывает, что любое значение, которое мы удерживаем, не может быть изменено с помощью какой-либо другой переменной.
Но у меня все еще есть путаница в моем сознании о том, что я упомянул в названии этого сообщения. Может ли кто-нибудь уточнить?
Ответы
Ответ 1
Типы значений могут быть либо изменчивыми, либо (по модулю некоторые странные краевые случаи) неизменяемыми, в зависимости от того, как вы их пишете.
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
, что является довольно сложным результатом.
См. этот вопрос для получения дополнительной информации о том, почему вы должны избегать изменяемых типов значений.
Ответ 2
все примитивные типы значений, такие как int, double, float, неизменяемы. Но структуры сами по себе являются mutable.so вы должны принять меры, чтобы сделать их неизменными, поскольку это может создать много путаниц.
Ответ 3
Любой экземпляр типа значения, который содержит любую информацию, может быть мутирован кодом, который может записать место хранения, в котором он содержится, и никакой тип-экземпляр значения не может быть изменен кодом, который не может записать место хранения, в котором он содержится. Эти характеристики делают частные хранилища хранилищ идеальных контейнеров данных с изменяемыми значениями типов во многих сценариях, поскольку они сочетают удобство обновления, которое связано с изменчивостью, с контролем, который будет получен из неизменности. Обратите внимание, что можно написать код для типа значения таким образом, чтобы он не мог мутировать существующий экземпляр без предварительного экземпляра (возможно, недавно созданного временного экземпляра), который содержит требуемые данные, и перезаписывания содержимого прежний экземпляр с содержимым последнего, но это не сделает тип значения более или менее изменчивым, чем отсутствовало бы такая способность. Во многих случаях он просто служит для того, чтобы сделать мутацию неудобной и заставить ее выглядеть как утверждение вроде:
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;
и последствия потоков будут намного яснее.