我经常读到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);
。但问题仍然存在——值类型在定义上不是不可变的吗?
更新
我认为至少涉及两个概念——变量或字段的可变性和变量值的可变性。
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);