现象

起因是工作中,在一个方法中对一个List进行了重赋值大概是,

1
2
3
// rezeptTekiyouUiList是参数
rezeptTekiyouUiList = rezeptTekiyouUiList.OrderBy(o => o.SubSeq).ThenBy(o => o.KomokuSeq).ToList();
// ...后续对rezeptTekiyouUiList继续操作

然后发现退出方法后,后续对list的操作不起效了…查了一会之后发现,不止是ToList,这样的也会失效:

1
2
3
4
5
6
7
8
9
10
11
public void ReSort(List<Test> list)
{
list = new List<Test>();
list.Add(new Test(){val = 1});
}
//甚至下面的也不行,val修改失败
public void ReSort(Test test)
{
test = new Test();
test.val = 2;
}

原因

那到这里问题就很明显了,是指针问题,不难得出一个结论:

  1. 进入方法后,参数会被分配空间并压在栈上。这个参数与调用处传入的变量不是一个东西,它只是调用处传入变量的一个浅拷贝,两者内容相等但不是同一个物体
  2. 执行test = new Test();,是在堆上新分配了一个实例并赋值其地址给参数,这时候这个参数和调用处传入变量已经一点关系也没有了。后续操作test.val = 2;也只是对堆上新实例操作。
  3. 方法体结束,栈帧unwind恢复,方法体内那个指着新堆中对象的参数凉了,而调用处传入得变量毫无变化。

至于.ToList()和new一样的,因为List不可变性。

解决

解决比较简单,就是ref or out传参。但如果内部用了lambda操作这个参数,那就没法用ref,所以最保险的是别用void了,直接return。