在下面列出的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();
}
}
答案 0 :(得分:7)
问题是VTEST_FSUB<V>
构造函数体在 VTEST_RUN
构造函数体之前正在执行。因此,当调用do_virtual
时,localSMT
仍为空。然后do_virtual
尝试在localSMT
上调用方法,因此异常。
基本上,层次结构中任何类的初始化顺序为:
有关详细信息,请参阅我的article on constructor chaining。
要学习的经验教训:
readonly
字段:如果您将值传递给构造函数链并在VTEST<V>
构造函数中设置它,那么您就不会遇到问题。 (不可否认,由于下一点...... readonly
字段仍然很痛苦。)do_virtual
中的VTEST_FSUB<V>
已经抽象,并且localSMT.doSomething
中的VTEST_RUN
被覆盖,则您很容易遇到同样的问题。它会在构造函数体运行之前仍然执行,这将是令人惊讶的。你在构造函数中调用的任何东西都是在一个部分初始化的对象上运行,这是一个不稳定的情况。答案 1 :(得分:3)
尝试:
public void do_virtual()
{
localSMT=new LocalSMT<V>();
localSMT.doSomething(list);
}
public class VTEST_FSUB<V> : VTEST<V>
中的
你在使用之前没有实现localSMT,所以它不起作用。
编辑:或
public class VTEST<V>
{
public List<V> list;
public LocalSMT<V> localSMT;
public VTEST()
{
list = new List<V>();
localSMT = new LocalSMT<V>();
}
}
在构造函数中初始化它,最好。
第二种解决方案更清洁。
答案 2 :(得分:1)
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);
}
确保当您尝试使用initialize他们的对象时!并且不要太担心,这是一个非常common problem的编码。