因为c#中的结构体是值类型,属性返回的是该结构体的副本而非引用。当你修改这个副本时,原对象中的数据并未被改变。要解决这个问题,你需要将修改后的结构体重新赋值给属性或字段。

为什么修改副本不影响原对象?
这是因为结构体在赋值或作为返回值传递时,会进行完整的内存拷贝。属性访问器(getter)返回的是一个临时的结构体实例,你对这个临时实例的任何修改都只作用于栈上的这块内存,而不会触及堆上或原始字段中存储的实际数据。

using System;
public struct Point
{
public int X;
public int Y;
}
public class Container
{
private Point _point;
// 属性返回的是_point的副本
public Point Point
{
get { return _point; }
set { _point = value; }
}
public void DemonstrateIssue()
{
// 初始化
_point = new Point { X = 10, Y = 20 };
// 获取副本并修改
Point p = Point; // 这里发生了拷贝
p.X = 999; // 修改的是副本
Console.WriteLine($"Original: {_point.X}, {_point.Y}"); // 输出: Original: 10, 20
Console.WriteLine($"Modified Copy: {p.X}, {p.Y}"); // 输出: Modified Copy: 999, 20
}
}
如何正确修改结构体成员?
由于直接通过属性获取的副本无法反向影响原对象,你必须先获取副本,修改它,然后将其重新赋值回属性或字段。或者,如果结构体定义允许,可以使用`ref`关键字或直接在字段级别操作(如果字段是公有的)。但在封装良好的代码中,推荐的做法是“读取-修改-写入”模式。

public class ContainerFixed
{
private Point _point;
public Point Point
{
get { return _point; }
set { _point = value; }
}
public void FixTheIssue()
{
// 1. 获取副本
Point p = Point;
// 2. 修改副本
p.X = 999;
p.Y = 888;
// 3. 将修改后的副本写回原对象
Point = p;
Console.WriteLine($"After Fix: {_point.X}, {_point.Y}"); // 输出: After Fix: 999, 888
}
}
使用Ref Struct或局部变量优化
如果在方法内部频繁操作结构体,可以考虑使用`ref`局部变量来避免不必要的拷贝,但这要求你直接操作字段或通过支持`ref`返回的属性(C# 7.0+)。不过,对于大多数场景,显式的“读取-修改-写入”是最清晰且兼容的方式。注意,如果结构体非常大,频繁的拷贝可能会带来性能开销,此时应考虑是否应该使用类(引用类型)来替代结构体。










