在下面列出的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();
}
}
Run Code Online (Sandbox Code Playgroud)
问题是,在VTEST_FSUB<V>构造函数体被执行之前的VTEST_RUN构造体.所以当do_virtual被调用时,localSMT仍然是null.然后do_virtual尝试调用方法localSMT,因此异常.
基本上,层次结构中任何类的初始化顺序是:
有关更多详细信息,请参阅有关构造函数链接的文章.
经验教训:
readonly字段:如果您将值传递给构造函数链并在VTEST<V>构造函数中设置它,那么您就不会遇到问题.(不可否认readonly,由于下一点,字段仍然会很痛苦......)do_virtual已经抽象VTEST_FSUB<V>并重写以调用localSMT.doSomething,您可能很容易遇到相同的问题VTEST_RUN.它仍然会在构造函数体运行之前执行,这将是令人惊讶的.在构造函数中调用的任何内容都在部分初始化的对象上运行,这是一种不稳定的情况.