为什么SecondChild类的重写方法不会被调用两次?

4

我不清楚为什么SecondChild类的DoSomething在初始化Child类时没有再次被调用。

class Parent
{
    public Parent()
    {
       DoSomething();
    }
    protected virtual  void DoSomething()
    {
        Console.WriteLine("Parent Method");
    }
}

class Child : Parent
{
    private string foo;

    public Child()
    {
        foo = "HELLO";
    }
    protected override void DoSomething()
    {
       Console.WriteLine(foo.ToLower());
    }
}

class SecondChild : Parent
{
    public SecondChild()
    {
        var c = new Child();
    }

    protected override void DoSomething()
    {
        Console.WriteLine("In second Child");
    }
}

class Program
{
    static void Main(string[] args)
    {
        SecondChild c = new SecondChild();
        Console.ReadLine();
    }
}

我原本期望在这里调用SecondChildDoSomething()方法两次,但实际上却调用了Child类中的DoSomething()方法,导致出现NullException错误。

2
请使用调试器:您只创建了一个SecondChild实例。在该构造函数中,您创建了一个Child实例(而不是SecondChild),那么为什么应该调用两次SecondChild.DoSomething() - René Vogt
1
你应该在问题中包含实际输出和期望输出。另外,阅读https://dev59.com/V3VD5IYBdhLWcg3wAWoO,它可能会解释一些事情。 - grek40
添加预期输出和实际输出。"called again" 太模糊了。 - H H
3
不要在构造函数中调用虚方法。 - Manfred Radlwimmer
顺便说一句:查看此问题以获取详细信息 - Manfred Radlwimmer
显示剩余3条评论
2个回答

4

我稍微调整了你的定义:

class Parent
{
    protected string foo;
    public Parent()
    {
        foo = "Parent1";
        DoSomething();
        foo = "Parent2";
    }
    protected virtual void DoSomething()
    {
        Console.WriteLine("Parent Method");
    }
}

class Child : Parent
{

    public Child()
    {
        foo = "HELLO";
    }
    protected override void DoSomething()
    {
        Console.WriteLine(foo.ToLower());
    }
}

class SecondChild : Parent
{
    public SecondChild()
    {
        var c = new Child();
    }

    protected override void DoSomething()
    {
        Console.WriteLine("In second Child");
    }
}

class Program
{
    static void Main(string[] args)
    {
        SecondChild c = new SecondChild();
        Console.ReadLine();
    }
}

这将输出:

在第二个子类中

parent1

为什么?看一下方法调用顺序:

new SecondChild()
  -> SecondChild:base()
      -> base.DoSomething() //virtual
    -> SecondChild.DoSomething()
  -> new Child()
    -> Child:base()
      -> base.DoSomething() //virtual
    -> Child.DoSomething()

0

当创建 SecondChild 类的实例时,DoSomething() 方法会被调用,但是当你创建 Child 类的实例时,首先会执行 Parent 类的构造函数,该构造函数调用了 Child 类的 DoSomething 方法,这是可以的。但是由于 Child 类的构造函数尚未执行,因此 foo 字段尚未初始化,执行 foo.ToLower() 会抛出空引用异常。

DoSomething 方法会被 Child 类和 SecondChild 类调用两次,但是对于 Child 类来说,由于 foo 为 null,所以会抛出异常。

因此,这里的棘手之处在于派生类的构造函数执行之前会执行基类的构造函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接