因为 list<t></t> 的索引器返回的是结构体实例的值拷贝,直接修改成员只会改变这个临时副本,原列表中的数据不会更新。要修改必须先将元素赋值给局部变量,修改后再重新赋值回列表。

为什么索引器返回的是值类型副本
当访问 list[i] 时,C# 编译器生成的代码会调用 get_Item 方法,该方法将结构体从数组中复制一份到栈上或寄存器中。由于结构体是值类型,这种复制是深拷贝(针对字段内容),修改副本不会影响堆上的原始数据。

using System;
using System.Collections.Generic;
public struct Point
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
var list = new List<Point>
{
new Point { X = 1, Y = 1 }
};
// 错误做法:修改无效
list[0].X = 99;
Console.WriteLine(list[0].X); // 输出 1
// 正确做法:通过局部变量修改
Point p = list[0];
p.X = 99;
list[0] = p;
Console.WriteLine(list[0].X); // 输出 99
}
}
如何高效批量修改结构体成员
对于大量数据,频繁创建和赋值局部变量会有性能开销。可以使用 ref 局部变量(C# 7.0+)直接引用列表中的内存位置,或者使用 Span<t></t> / Memory<t></t> 进行零拷贝操作。

using System;
using System.Collections.Generic;
public struct Point
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
var list = new List<Point>
{
new Point { X = 1, Y = 1 },
new Point { X = 2, Y = 2 }
};
// 使用 ref 局部变量直接修改
ref Point p = ref list[0];
p.X = 88;
// 验证结果
Console.WriteLine(list[0].X); // 输出 88
Console.WriteLine(p.X); // 输出 88
}
}
List内部存储结构对结构体的影响
List<t></t> 底层使用数组存储元素。当结构体较大时,每次通过索引器访问都会触发一次内存复制。如果结构体包含引用类型字段,这些字段的引用会被复制,但对象本身共享。理解这一点有助于避免在高性能场景下因频繁装箱或复制导致的性能瓶颈。


















