【问题标题】:A NULL object in a List stays NULL even after initialization即使在初始化之后,List 中的 NULL 对象也保持为 NULL
【发布时间】:2020-12-15 00:50:08
【问题描述】:

请看下面的代码:

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 仍然为空 - 这是预期的。该列表应该包含对 myObject2 的引用,即使它为空。

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

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

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

        myObject1 = new MyClass();

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

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

【问题讨论】:

  • myObject2 没有被初始化,所以你有myObject1.otherObjectsOfSameClass = new List&lt;MyClass&gt; { null };所以例外......即使你创建了一个你分配给myObject2 之后,你在列表中有null。跨度>
  • 在您重新分配变量时,列表项和变量不再引用同一个对象。变量和列表保存值,有时这些值是引用。有时,两个变量、两个列表项或一个混合项具有相同的值,可以是对同一对象的引用。但重新分配一个不会影响另一个。
  • 知道了。所以我只是在将它们添加到列表之前初始化这些对象,这是一个简单的修复。非常感谢你们。

标签: c# class object reference nullreferenceexception


【解决方案1】:

列表的变量和元素存储值。对于像MyClass 这样的引用类型,该值要么是对对象 的引用,要么是值null - 什么都没有。

在工作情况下,

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

列表包含变量myObject1 存储的引用。 myObject1 存储对 MyClass 对象的引用,而不是 null,因此列表还存储对同一对象的引用,因此当您访问列表时,没有例外。注意myObject1myObject2.otherObjectsOfSameClass[0] 的值是不相关的。 碰巧它们的值是对同一个对象的引用,但否则更改其中一个对象的值不会影响另一个。例如,做:

myObject1 = null;

也不会使 myObject2.otherObjectsOfSameClass[0] 为空。

OTOH,当它运行时:

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

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

myObject2 = new MyClass();

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

【讨论】:

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

这是有道理的——此时初始化myList = new List&lt;MyClass&gt; { myObject1, myObject2 }; 时,您正在创建一个新列表,并且该列表中的值将评估为空。您稍后初始化 myObject1 或 myObject2 的事实不会改变您在 myList 中存储空值的事实。

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

【讨论】:

  • 好的,我想我明白了。我认为即使是一个空对象也有一个内存地址,但是那个内存还没有被使用。所以,考虑到我的例子,我想我应该首先初始化 myObject1 和 myObject2,然后才将它们添加到彼此的列表中?
猜你喜欢
  • 2021-04-04
  • 2021-02-22
  • 1970-01-01
  • 1970-01-01
  • 2021-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多