初始化容器时 C# 中的 NullReferenceException
本文关键字:中的 NullReferenceException 初始化 | 更新日期: 2023-09-27 18:33:34
在下面列出的C#代码中,我得到一个"NullReferenceException",并显示错误:
"对象引用未设置为对象的实例">
我想错误与继承和/或模板定义有关。列表被初始化,调试时我可以确认列表不指向 NULL。我不知道如何以另一种方式做到这一点。(很抱歉类名/结构令人困惑(。例外发生在这里:this.localSMT.doSomething(base.list(;
public class VTEST<V>
{
public List<V> list;
public LocalSMT<V> localSMT;
public VTEST()
{
list = new List<V>();
}
}
public class VTEST_FSUB<V> : VTEST<V>
{
public VTEST_FSUB()
{
do_virtual();
}
public void do_virtual()
{
this.localSMT.doSomething(base.list);
}
}
public class VTEST_RUN : VTEST_FSUB<int>
{
public VTEST_RUN()
{
localSMT = new VTEST_SUB();
}
}
public class LocalSMT<V>
{
public LocalSMT() { }
public virtual void doSomething(List<V> value) { }
}
public class VTEST_SUB : LocalSMT<int>
{
public VTEST_SUB(){}
public override void doSomething(List<int> value) {
System.Console.WriteLine("VTEST_SUB VIRTUAL");
}
}
class Program
{
Program() {}
static void Main(string[] args)
{
VTEST_RUN run = new VTEST_RUN();
}
}
问题是 VTEST_FSUB<V>
构造函数体在VTEST_RUN
构造函数体之前执行。因此,当调用do_virtual
时,localSMT
仍然是空的。然后do_virtual
尝试在localSMT
上调用一个方法,因此异常。
基本上,层次结构中任何类的初始化顺序为:
- 初始化在声明
- 点在初始值设定项中声明的变量(任何其他变量仅具有变量类型的默认值(
- 链接到基类初始化
- 执行构造函数体
有关更多详细信息,请参阅我关于构造函数链接的文章。
要吸取的教训:
- 避免公共字段。如果您使用私有字段,则很容易找到读取和写入它们的每一段代码
- 理想情况下,使用
readonly
字段:如果您将值传递到构造函数链并将其设置在VTEST<V>
构造函数中,则不会有问题。(诚然,readonly
字段仍然会因为下一点而痛苦...... - 避免在构造函数中调用虚拟方法。在这种情况下,这不是问题,但是如果
do_virtual
在VTEST_FSUB<V>
中是抽象的,并且被覆盖以在VTEST_RUN
中调用localSMT.doSomething
,则很容易遇到相同的问题。它仍然会在构造函数主体运行之前执行,这将是令人惊讶的。您在构造函数中调用的任何内容都在部分初始化的对象上运行,这是一个不稳定的情况。 - 避免大型继承层次结构。与他们一起工作和推理是一种痛苦。
- 遵循 .NET 命名约定!你的代码部分难以阅读,因为它太不合时宜了。即使您只是提供示例代码,至少也要遵循大写约定。
尝试:
public void do_virtual()
{
localSMT=new LocalSMT<V>();
localSMT.doSomething(list);
}
在public class VTEST_FSUB<V> : VTEST<V>
您在使用之前没有安装本地SMT,因此它不起作用。
编辑:或
public class VTEST<V>
{
public List<V> list;
public LocalSMT<V> localSMT;
public VTEST()
{
list = new List<V>();
localSMT = new LocalSMT<V>();
}
}
最好在构造函数中初始化它。
第二种解决方案是更清洁。
public class VTEST_RUN : VTEST_FSUB<int>
{
public VTEST_RUN()
{
localSMT = new VTEST_SUB(); // BAD! localSMT isn't initialized yet!
}
}
我相信你没有new
你的一个对象:
public void do_virtual()
{
localSMT = new LocalSMT<V>();
localSMT.doSomething(list);
}
确保在尝试使用对象时初始化它们! 而且不要太担心,这是编码中非常普遍的问题。