Я часто читаю, что struct
s должны быть неизменными - не по определению?
Считаете ли вы int
неизменным?
int i = 0;
i = i + 123;
Кажется, все в порядке - мы получаем новый int
и присваиваем его обратно i
. Как насчет этого?
i++;
Хорошо, мы можем думать об этом как о ярлыке.
i = i + 1;
А как насчет struct
Point
?
Point p = new Point(1, 2);
p.Offset(3, 4);
Действительно ли это изменяет точку (1, 2)
? Разве мы не должны думать об этом как о сокращении для следующего с Point.Offset()
, возвращающим новую точку?
p = p.Offset(3, 4);
Основой этой мысли является то, как тип значения без тождества может быть изменяемым? Вы должны взглянуть на него как минимум дважды, чтобы определить, изменился ли он. Но как вы можете сделать это без личности?
Я не хочу усложнять рассуждения об этом, рассматривая параметры ref
и бокс. Я также знаю, что p = p.Offset(3, 4);
выражает неизменность гораздо лучше, чем p.Offset(3, 4);
. Но остается вопрос - не являются ли типы значений неизменяемыми по определению?
UPDATE
Я думаю, что здесь задействованы как минимум два понятия - изменчивость переменной или поля и изменчивость значения переменной.
public class Foo
{
private Point point;
private readonly Point readOnlyPoint;
public Foo()
{
this.point = new Point(1, 2);
this.readOnlyPoint = new Point(1, 2);
}
public void Bar()
{
this.point = new Point(1, 2);
this.readOnlyPoint = new Point(1, 2); // Does not compile.
this.point.Offset(3, 4); // Is now (4, 6).
this.readOnlyPoint.Offset(3, 4); // Is still (1, 2).
}
}
В примере мы имеем поля - изменяемые и неизменяемые. Поскольку поле типа значения содержит все значение, тип значения, хранящийся в неизменяемом поле, также должен быть неизменным. Я все еще удивлен результатом - я не ожидал, что поле readonly останется неизменным.
Переменные (кроме констант) всегда изменяемы, поэтому они не налагают никаких ограничений на изменчивость типов значений.
Кажется, ответ не такой уж прямой, поэтому я перефразирую вопрос.
Учитывая следующее.
public struct Foo
{
public void DoStuff(whatEverArgumentsYouLike)
{
// Do what ever you like to do.
}
// Put in everything you like - fields, constants, methods, properties ...
}
Можете ли вы привести готовую версию Foo
и пример использования - который может включать ref
параметры и упаковку - чтобы не было возможности переписать все случаи
foo.DoStuff(whatEverArgumentsYouLike);
с
foo = foo.DoStuff(whatEverArgumentsYouLike);