无法修改“System.Collections.Generic.List<SueseGeometry.Vector3>.this[int]”的返回值,因为它不是变量
使用List写代码的时候遇到了一个“怪异”的现象,无法修改List中对象的属性值。
下面就具体使用代码一起来看一下:
private void test()
{
List<Vector3> list = new List<Vector3>();
list.Add(new Vector3(1, 0, 0));
list.Add(new Vector3(2, 0, 0));
list.Add(new Vector3(3, 0, 0));
// 使用下面这句代码的时候就会出现编译错误
// 错误提示如下
// 无法修改"List<Vector3>.this[int]"的返回值,因为它不是变量
list[0].x = 4f;
}
这个就让人比较纳闷了,然后我们尝试使用一下Vector3中的Set方法
private void test()
{
List<Vector3> list = new List<Vector3>();
list.Add(new Vector3(1, 0, 0));
list.Add(new Vector3(2, 0, 0));
list.Add(new Vector3(3, 0, 0));
Debug.Log("list[0] = " + list[0]);
list[0].Set(4f, 0, 0);
Debug.Log("list[0] = " + list[0]);
}
这次编译器不会报出任何错误,但是通过打印可以发现,两次打印的结果是一样的,O~Shit!
这和我们平常的使用不太一样啊,哪里出问题了呢?
好吧,既然这样,咱们就继续探索一下,新建一个类,然后重新走一边试试
public class AClass
{
public int x;
public AClass(int x)
{
this.x = x;
}
}
private void test()
{
List<AClass> list = new List<AClass>();
list.Add(new AClass(1));
list.Add(new AClass(2));
list.Add(new AClass(3));
Debug.Log("list[0].x = " + list[0].x);
list[0].x = 4;
Debug.Log("list[0].x = " + list[0].x);
}
这次通过打印我们可以发现,list[0].x 的值是被改变了的。到这里,我们就需要想想这到底发生了什么。。
我们需要看看Vector3 和我们创建的 AClass 的不同。这时候你就会发现,Vector3 并不是class,而是一个struct。或许你会问这又代表了什么?
我们知道 list[i] 是继承 IList 中的方法
object this[int index] { get; set; }
那么当get的时候如果是struct,那么它其实就是一个值传递; 如果是class,它传递的是对象的地址。
再通俗一点就是说:值传递 它返回的是一个临时拷贝,而当你改变这个拷贝的时候,对原来的object是不会起到任何作用的,因此编译器认为这是毫无意义的,就从源头上禁止了这种做法。
当然这是作为左值,尝试去改变的时候,如果是右值,只是使用了它的属性值,这还是可以的。
所以,探索到这里,我们就知道了,这其实就是一个值传递和地址传递的区别,这就不足为怪了。