static void AAA() {
Test[] ts = new Test[1];
ts[0] = new Test(1, "a");
ts[0].a = 123; //完全没有问题
}
static void BBB() {
List<Test> ts = new List<Test>();
ts.Add(new Test(1, "a"));
ts[0].a = 123; //直接报错,说是“无法修改xxx的返回值,因为它不是变量”
}
struct Test {
public int a;
public string b;
public Test(int a, string b) {
this.a = a;
this.b = b;
}
}
是因为数组索引直接是指向了结构的地址,然后修改地址内存中的数据不报错,而集合是通过索引器返回拷贝的结构体,修改拷贝的数据没有意义,所以微软直接给报错了吗
你理解的是正确的,微软源头上直接禁止了这种操作。
解决办法:
1.改成class引用类型,这样,就成了一个对象(引用类型),就会返回在堆上的实际地址,修改也会反映到实际的对象
2.设置一个中间临时变量,然后再替换整个原来的struct值。这样实际上是替换整个struct。
根本原因是:
不管存的是什么,数组返回的是对象引用,List<T>返回的是对应的泛型类型,返回值类型时不能直接修改其数据。
List<T>底层也是通过数组实现的,就是返回的时候会转换成对应的泛型类型。
数组索引器返回时会新建一个对象指向对应索引下的内容(值也是一个特殊的对象)并返回其引用,对于值类型返回的引用和值的变量名起到的作用是一样的,所以能在返回的引用上访问结构体的成员。