List 中的 NULL 对象即使在初始化后仍保持 NULL

A NULL object in a List stays NULL even after initialization

提问人:Justinas Rubinovas 提问时间:12/15/2020 最后编辑:Justinas Rubinovas 更新时间:12/15/2020 访问量:1180

问:

请看下面的代码:

public class MainClass
{
    MyClass myObject1, myObject2;

    public MainClass()
    {
        myObject1 = new MyClass();
        myObject1.otherObjectsOfSameClass = new List<MyClass> { myObject2 };

        myObject2 = new MyClass();
        myObject2.otherObjectsOfSameClass = new List<MyClass> { myObject1 };
        
        myObject2.otherObjectsOfSameClass[0].TestMethod(); // works fine
        myObject1.otherObjectsOfSameClass[0].TestMethod(); // throws null reference exception
    }
}

class MyClass
{
    public List<MyClass> otherObjectsOfSameClass;

    public bool TestMethod()
    {
        return true;
    }
}

我在这里试图实现的是存储几个 MyClass 类型的对象,这些对象包含对同一类型的其他成员的引用。当我初始化 MainClass 构造函数中每个对象的 otherObjectsOfSameClass 列表时,我会将另一个对象添加到该列表中。当我初始化 myObject1 时,myObject2 仍然是 null - 这是预期的。该列表应包含对 myObject2 的引用,即使它为 null。

但是,即使在我初始化 myObject2 之后,它在 myObject1 的 otherObjectsOfSameClass 列表中仍然是 null。出于某种原因,该列表中的对象引用不会更新。有人可以解释一下这种行为吗?我是否误解了这里的基本内容?

编辑:我意识到这可以通过更简单的测试代码重现:

        List<MyClass> myList = new List<MyClass> { myObject1, myObject2 };

        myObject1 = new MyClass();

        myObject1.TestMethod(); // works fine
        myList[0].TestMethod(); // throws null reference exception

似乎将未初始化的对象添加到列表中并在之后对其进行初始化不会在列表中更改它 - 即使它应该通过引用而不是通过值添加......

C# 对象 引用 NullReferenceException

评论

2赞 12/15/2020
myObject2未初始化,所以你有这样的异常......即使您创建了一个分配给之后的人,列表中的 NULL 也会为。myObject1.otherObjectsOfSameClass = new List<MyClass> { null };myObject2
1赞 Anthony Pegram 12/15/2020
在重新分配变量的那一刻,列表项和变量不再引用同一对象。变量和列表保存值,有时这些值是引用。有时,两个变量、两个列表项或一个组合包含相同的值,该值可以是对同一对象的引用。但是重新分配一个不会影响另一个。
0赞 Justinas Rubinovas 12/15/2020
明白了。因此,我只是在将这些对象添加到列表之前对其进行了初始化,这是一个简单的解决方法。非常感谢你们,伙计们。

答:

2赞 cppNoob 12/15/2020 #1

这是有道理的 - 此时初始化时,您正在创建一个新列表,该列表中的值将计算为 null。稍后初始化 myObject1 或 myObject2 这一事实不会改变在 myList 中存储 null 的事实。myList = new List<MyClass> { myObject1, myObject2 };

这是因为 myObject1 在实例化时为 null - 它没有指向的内存地址,也没有它引用的对象。另一方面,如果您要初始化然后初始化,则它不会是未定义的,并且将具有对 myObject1 的引用,因此如果您更新 myObject1,更新也将反映在myObject1 = new someObject()myListmyList

评论

0赞 Justinas Rubinovas 12/15/2020
好吧,我想我明白了。我以为即使是空对象仍然有一个内存地址,但该内存尚未使用。所以,考虑到我的例子,我想我应该首先初始化 myObject1 和 myObject2,然后才将它们添加到彼此的列表中?
2赞 Sweeper 12/15/2020 #2

列表的变量和元素存储值。对于像这样的引用类型,该值要么是对对象的引用,要么是值 - nothing。MyClassnull

在工作案例中,

myObject2.otherObjectsOfSameClass = new List<MyClass> { myObject1 };

该列表包含变量存储的引用。 存储对对象的引用,而不是 null,因此该列表还存储对同一对象的引用,因此在访问该列表时,不会出现异常。请注意,和的值是不相关的。碰巧的是,它们的值是对同一对象的引用,但除此之外,更改其中一个的值不会影响另一个。例如,执行以下操作:myObject1myObject1MyClassmyObject1myObject2.otherObjectsOfSameClass[0]

myObject1 = null;

也不会使 null 也是如此。myObject2.otherObjectsOfSameClass[0]

OTOH,当它运行时:

myObject1.otherObjectsOfSameClass = new List<MyClass> { myObject2 };

myObject2stores ,因此列表存储 null。同样,和的值是不相关的。碰巧它们都是空的。然后你说:nullmyObject2myObject1.otherObjectsOfSameClass[0]

myObject2 = new MyClass();

这将 的值更改为对对象的引用。这对 的值没有影响。毕竟,它们是两个不同的变量。myObject2myObject1.otherObjectsOfSameClass[0]

评论

0赞 Justinas Rubinovas 12/15/2020
非常感谢您如此详尽的解释。我现在明白了。我只是认为,即使是一个未启动但已声明的对象也已经有一个指针,应该传递给该列表。现在一切都清楚了。再次感谢!
0赞 cppNoob 12/15/2020
@Sweeper当你说“碰巧它们的值是对同一对象的引用,但除此之外,更改其中一个的值不会影响另一个。例如,执行: myObject1 = null;”在此示例中,您将删除引用,而不是更新对象。尝试在 myObject1 上实际设置一些属性,它也会更新myObject2.otherObjectsOfSameClass[0]
0赞 Sweeper 12/15/2020
@cloudComputer107 如果您正在设置 的某些属性,则不会“更改存储在 中的值”。要更改变量的值,您应该在该变量上使用,即 . 正在更改 的值。它与 的值无关。但是,您正在改变存储在 中的引用所引用的对象。myObject1myObject1=myObject1 = ...myObject1.SomeProperty = ...SomePropertymyObject1myObject1
0赞 cppNoob 12/15/2020
是的,你正在改变它,这就是为什么我认为说这些值不相关是令人困惑的