PAYATHON 2026

为什么给 cl1 赋值后,List<T> 中对应的元素仍为 null?

排障赵师傅

l_my.Add(cl1) 保存的是调用时 cl1 的引用值。当时 cl1 为 null,列表中添加的也就是 null。之后执行 cl1 = new MyCl1();,只会改变字段 cl1 的值,已经存入列表的元素不会跟着更新。

为什么引用类型也会出现这种情况?

引用类型变量保存的是对象的引用。赋值、传参或添加到列表时,复制的都是引用值,不会复制对象本身。

cl1 和 l_my[0] 是两个独立的存储位置。List<T>.Add(T item) 按值接收参数,因此列表元素与字段之间没有自动同步关系。

执行步骤cl1 的值l_my[0] 的值
字段默认初始化后null尚无元素
l_my.Add(cl1) 后nullnull
init_cl1() 后指向新建的 MyCl1 对象null

下面这条语句会创建一个对象,并把它的引用赋给 cl1:

cl1 = new MyCl1();

它没有给 l_my[0] 重新赋值,所以列表元素仍然是 null。接着从列表中读取这个元素,得到的 my2 也为 null:

MyCl1 my2 = l_my[0];

如何让列表保存初始化后的对象?

先创建对象,再添加到列表

把 init_cl1() 放在 Add 之前,就能让字段和列表元素引用同一个对象:

public Form1()
{
    InitializeComponent();

    List<MyCl1> l_my = new List<MyCl1>();

    init_cl1();
    l_my.Add(cl1);

    MyCl1 my2 = l_my[0];
    // my2 与 cl1 引用同一个对象
    // object.ReferenceEquals(cl1, my2) 为 true
}

此时,Add 复制的是新建对象的引用,字段和列表元素都能访问这个对象。

如果已经添加了 null,就显式更新列表元素

如果业务流程要求先添加元素、后创建对象,就需要在初始化完成后,给列表中的对应位置重新赋值:

List<MyCl1> l_my = new List<MyCl1>();
l_my.Add(cl1); // 此时添加的是 null

init_cl1();
l_my[0] = cl1; // 将新对象的引用写入列表

MyCl1 my2 = l_my[0];
// my2 与 cl1 引用同一个对象

l_my[0] = cl1 会更新已有元素。如果再次调用 l_my.Add(cl1),则会在列表末尾追加一个元素,原来的第一个元素仍然是 null。

修改对象内容与重新赋值有什么区别?

当两个位置保存同一个对象的引用时,通过其中一个引用修改对象内容,另一个引用也能读到修改后的内容。

例如,给 MyCl1 添加一个属性:

public class MyCl1
{
    public int Value { get; set; }
}

然后执行以下代码:

MyCl1 cl1 = new MyCl1();
List<MyCl1> l_my = new List<MyCl1>();
l_my.Add(cl1);

cl1.Value = 10;
// l_my[0].Value 为 10

cl1 = new MyCl1 { Value = 20 };
// cl1.Value 为 20
// l_my[0].Value 仍为 10

cl1.Value = 10 修改的是两个引用所指向的同一个对象。之后执行 cl1 = new MyCl1 { Value = 20 };,cl1 指向了另一个对象,列表元素仍然引用原来的对象。

注意事项

原代码中的 MyCl1 cl1; 声明的是实例字段。引用类型字段的默认值为 null,因此可以在显式赋值前读取。如果把同样的声明写在方法内,cl1 就是局部变量,必须先赋值再使用,否则会出现编译错误。

null 表示没有引用任何对象,并不是一个等待初始化的对象。列表元素为 null 时,没有对象可供修改;需要先创建对象,再把引用赋给要使用它的字段或列表元素。

备注:内容仅供参考。