Понятия изменчивости и неизменности имеют разные значения применительно к структурам и классам.Ключевой аспект (часто ключевой недостаток) изменяемых классов заключается в том, что Foo
имеет поле Bar
типа List<Integer>
, которое содержит ссылку на список, содержащий (1,2,3), другой код, который имеетссылка на этот же список может изменить его, так что Bar
содержит ссылку на список, содержащий (4,5,6), , даже если этот другой код не имеет доступа к Bar
.Напротив, если бы Foo
имело поле Biz
типа System.Drawing.Point
, единственным способом, которым что-либо могло изменить любой аспект Biz
, было бы , чтобы иметь доступ на запись к этому полю .
Поля (открытые и закрытые) структуры могут быть изменены любым кодом, который может изменить местоположение хранилища, в котором хранится структура, и не могут быть изменены каким-либо кодом, который не может изменить местоположение хранилища, в котором он хранится.Если вся информация, инкапсулированная в структуре, содержится в ее полях, такая структура может эффективно комбинировать управление неизменяемым типом с удобством изменяемого типа, если структура не закодирована таким образом, чтобы устранить такое удобство (привычка, которую, к сожалению, рекомендуют некоторые программисты Microsoft).
«Проблема» со структурами заключается в том, что когда метод (включая реализацию свойства) вызывается для структуры в контексте только для чтения (или неизменном месте)), система копирует структуру, выполняет метод для временной копии и молча отбрасывает результат.Такое поведение привело к тому, что программисты выдвинули досадную идею о том, что способ избежать проблем с методами мутации состоит в том, чтобы многие структуры запрещали кусочные обновления, когда проблем можно было бы лучше избежать, просто просто заменив свойства открытыми полями .
Кстати, некоторые люди жалуются, что когда свойство класса возвращает удобно изменяемую структуру, изменения в структуре не влияют на класс, из которого оно получено.Я бы сказал, что это хорошо - тот факт, что возвращаемый элемент является структурой, делает поведение понятным (особенно, если это структура с открытыми полями).Сравните фрагмент с гипотетической структурой и свойством Drawing.Matrix
с фрагментом, использующим фактическое свойство этого класса в Microsoft:
// Hypothetical struct
public struct {
public float xx,xy,yx,yy,dx,dy;
} Transform2d;
// Hypothetical property of "System.Drawing.Drawing2d.Matrix"
public Transform2d Transform {get;}
// Actual property of "System.Drawing.Drawing2d.Matrix"
public float[] Elements { get; }
// Code using hypothetical struct
Transform2d myTransform = myMatrix.Transform;
myTransform.dx += 20;
... other code using myTransform
// Code using actual Microsoft property
float[] myArray = myMatrix.Elements;
myArray[4] += 20;
... other code using myArray
Рассматривая фактическое свойство Microsoft, можно ли определить,запись в myArray[4]
повлияет на myMatrix
?Даже глядя на страницу http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.matrix.elements.aspx есть ли способ сказать?Если бы свойство было написано с использованием структурного эквивалента, не было бы никакой путаницы;свойство, которое возвращает структуру, не вернет ни больше, ни меньше, чем текущее значение шести чисел.Изменение myTransform.dx
было бы не чем иным, как записью в переменную с плавающей запятой, которая не была привязана ни к чему другому.Любой, кому не нравится тот факт, что изменение myTransform.dx
не влияет на myMatrix
, должен быть в равной степени раздражен тем, что написание myArray[4]
также не влияет на myMatrix
, за исключением того, что независимость myMatrix
и myTransform
очевидно, в то время как независимость myMatrix
и myArray
не является.