当您访问字段时,您正在访问实际的结构。当您通过属性访问它时,您调用一个方法来返回存储在属性中的任何内容。对于结构体,它是值类型,您将得到该结构体的副本。显然该副本不是变量并且无法更改。
C# 语言规范 5.0 的“1.7 结构”部分说:
对于类,两个变量可以引用相同的变量
对象,因此对一个变量的操作可能会影响
另一个变量引用的对象。对于结构体,变量
每个人都有自己的数据副本,并且不可能
对其中一个的操作会影响另一个。
这说明您将收到该结构的副本,并且无法修改原始结构。但是,它没有描述为什么不允许这样做。
规范的“11.3.3”节:
当结构体的属性或索引器是赋值的目标时,
与属性或索引器访问关联的实例表达式
必须归类为变量。如果实例表达式是
分类为值时,会发生编译时错误。这是描述的
详细信息请参见第 7.17.1 节。
因此,从 get 访问器返回的“东西”是一个值,而不是一个变量。这解释了错误消息中的措辞。
该规范还在第 7.17.1 节中包含一个与您的代码几乎相同的示例:
鉴于声明:
struct Point
{
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int X {
get { return x; }
set { x = value; }
}
public int Y {
get { return y; }
set { y = value; }
}
}
struct Rectangle
{
Point a, b;
public Rectangle(Point a, Point b) {
this.a = a;
this.b = b;
}
public Point A {
get { return a; }
set { a = value; }
}
public Point B {
get { return b; }
set { b = value; }
}
}
在示例中
Point p = new Point();
p.X = 100;
p.Y = 100;
Rectangle r = new Rectangle();
r.A = new Point(10, 10);
r.B = p;
允许对 p.X、p.Y、r.A 和 r.B 进行赋值,因为 p 和 r 是变量。然而,在示例中
Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;
这些赋值都是无效的,因为 r.A 和 r.B 不是变量。