【发布时间】:2010-10-26 11:41:44
【问题描述】:
我经常读到structs 应该是不可变的——它们不是根据定义吗?
你认为int 是不可变的吗?
int i = 0;
i = i + 123;
似乎没问题 - 我们得到一个新的 int 并将其分配回 i。这个呢?
i++;
好吧,我们可以把它当成一个捷径。
i = i + 1;
structPoint 呢?
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);
【问题讨论】:
标签: c# .net immutability value-type