我在下面的代码片段中总结了我的问题
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace St
{
public class Animal
{
public Animal()
{
Speak();
}
public virtual void Speak()
{
Console.WriteLine("Animal speak");
}
}
public class Dog:Animal
{
private StringBuilder sb = null;
public Dog()
{
sb=new StringBuilder();
}
public override void Speak()
{
Console.WriteLine("bow...{0}",sb.Append("bow"));
}
}
class Program
{
static void Main(string[] args)
{
Dog d=new Dog();
}
}
}
Run Code Online (Sandbox Code Playgroud)
当我编译它时没有错误但是当我运行它时我得到对象引用错误.
Ree*_*sey 11
问题是你在Animal的构造函数中调用了一个虚方法.
这是一种危险的做法 - 正是出于这个原因.问题是,当你构造一个Dog时,首先运行"Animal"(基类)构造函数.此时,它打电话Speak().但是,Dog的Speak方法依赖于已经运行的Dog的构造函数,因此sb尚未初始化并且仍然存在null.
通常,构造函数中的虚方法调用是一个非常糟糕的想法 - 并且是设计缺陷的标志.我在这里推荐一种不同的方法.
我对此进行重新修改的建议是简单地Speak()从构造函数中删除它.我会把这段代码写成:
public class Animal
{
public Animal()
{
// Don't do this in the constructor
// Speak();
}
public virtual void Speak()
{
Console.WriteLine("Animal speak");
}
}
public class Dog : Animal
{
private StringBuilder sb = null;
public Dog()
{
sb = new StringBuilder();
}
public override void Speak()
{
Console.WriteLine("bow...{0}", sb.Append("bow"));
}
}
class Program
{
static void Main(string[] args)
{
Dog d = new Dog();
d.Speak();
}
}
Run Code Online (Sandbox Code Playgroud)
从逻辑的角度来看,这对我来说更有意义.这一行:
Dog d = new Dog();
Run Code Online (Sandbox Code Playgroud)
负责单一行动 - 构建新行动Dog.作为班级的消费者,我不希望它执行复杂的操作(即:说话) - 仅仅是为了正确地创建和设置Dog及其内部状态.
当我想要它发言时,我特意打电话:
d.Speak();
Run Code Online (Sandbox Code Playgroud)