问题描述
好的,我会开始我的问题,说我了解可变结构背后的邪恶,但我正在使用 SFML.net 并使用大量 Vector2f 和此类结构.
Ok, I'll start my question saying that I understand the evil behind mutable structs, but I'm working with SFML.net and using a lot of Vector2f and such structs.
我不明白的是为什么我可以拥有并更改类中的字段的值,而不能对同一个类中的属性执行相同操作.
What I don't get it is why I can have, and change the values of, a field in a class and can't do the same with a property, in the very same class.
看看这段代码:
using System;
namespace Test
{
public struct TestStruct
{
public string Value;
}
class Program
{
TestStruct structA;
TestStruct structB { get; set; }
static void Main(string[] args)
{
Program program = new Program();
// This Works
program.structA.Value = "Test A";
// This fails with the following error:
// Cannot modify the return value of 'Test.Program.structB'
// because it is not a variable
//program.structB.Value = "Test B";
TestStruct copy = program.structB;
copy.Value = "Test B";
Console.WriteLine(program.structA.Value); // "Test A"
Console.WriteLine(program.structB.Value); // Empty, as expected
}
}
}
注意:我将构建自己的类来覆盖相同的功能并保持我的可变性,但我看不出为什么我可以做一个而不能做其他的技术原因.
note: I'll build my own classes to cover the same functionality and keep with my mutability, but I can't see a technical reason why I can do one and can't do other.
推荐答案
当您访问一个字段时,您正在访问实际的结构.当您通过属性访问它时,您调用了一个方法,该方法返回存储在属性中的任何内容.在结构体是值类型的情况下,您将获得该结构体的副本.显然,该副本不是变量,无法更改.
When you access a field, you are accessing the actual struct. When you access it through property, you call a method that returns whatever is stored in the property. In the case of a struct, which is a value type, you will get back a copy of the struct. Apparently that copy is not a variable and cannot be changed.
C# 语言规范 5.0 的1.7 结构"部分说:
Section "1.7 Structs" of the C# language specification 5.0 says:
对于类,两个变量可以引用相同的对象,因此对一个变量的操作可能会影响另一个变量引用的对象.对于结构,变量每个人都有自己的数据副本,这是不可能的一个操作会影响另一个.
这说明您将收到结构的副本,并且无法修改原始结构.但是,它没有说明为什么不允许这样做.
That explains that you will receive a copy of the struct and not be able to modify the original struct. However, it doesn't describe why it isn't allowed.
规范的11.3.3"部分:
Section "11.3.3" of the specifcation:
当结构的属性或索引器是赋值的目标时,与属性或索引器访问相关联的实例表达式必须归类为变量.如果实例表达式是归类为值,则会发生编译时错误.这是描述在 §7.17.1 中进一步详细说明.
所以从 get 访问器返回的东西"是一个值而不是一个变量.这解释了错误消息中的措辞.
So the returned "thing" from the get accessor is a value and not a variable. That explains the wording in the error message.
规范在第 7.17.1 节中还包含一个与您的代码几乎相同的示例:
The specification also contains an example in section 7.17.1 that is nearly identical to your code:
鉴于声明:
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 是变量.但是,在示例中
the assignments to p.X, p.Y, r.A, and r.B are permitted because p and r are variables. However, in the example
Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;
赋值都是无效的,因为 r.A 和 r.B 不是变量.
the assignments are all invalid, since r.A and r.B are not variables.
这篇关于访问和更改结构作为属性与作为字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!