Я часто читаю, что struct
должен быть неизменным - не по определению?
Вы считаете, что 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);