转换为基类,并调用其虚方法导致stackoverflow异常

时间:2013-11-19 07:36:29

标签: c#

考虑以下代码:

public class Person
{
    public virtual void UpdateLastLogin()
    {
        // business of last login here
    }
}

public class Student : Person
{
    public override void UpdateLastLogin()
    {
        // logging something specific to person
        ((Person)this).UpdatelastLogin();
    }
}

为什么上面的代码抛出STACKOVERFLOW异常?

但这不是:

public class Person
{
    public virtual void UpdateLastLogin()
    {
        // business of last login here
    }
}

public class Student : Person
{
    public override void UpdateLastLogin()
    {
        // logging something specific to person
        base.UpdatelastLogin();
    }
}

2 个答案:

答案 0 :(得分:16)

这是因为 base 关键字禁用了虚拟方法调用,但是没有投射。

让我们分解一下:

使用virtualoverride,C#有一个算法来查找正确的调用方法。该算法称为虚方法调用

当C#编译器要调用具有override修饰符的方法时,它会尝试查找最重写方法。也就是说,它沿着运行时类型的继承层次结构向下找到最重写的方法。在这种情况下,当您将Student强制转换为基类Person时,在运行时中,您真正拥有的是来自Person的派生类。因此,C#编译器尝试查找最重写方法,即Student类中存在的方法,并调用该方法。但是该方法再次尝试将Student转换为Person,然后链条继续进行。因此,您会看到StackOverflowException

但是,当您使用base调用重写的基本方法时,编译器会将该方法(Person.UpdateLastLogin)视为非虚方法< / strong>并且不会将虚拟方法调用解决方案应用于它。

C#规范对overridevirtual有一个非常合理的解释。我建议您阅读 17.5.3虚拟方法 17.5.4覆盖方法部分。具体引用规范:

  

base-access禁用虚拟调用机制,只是将基本方法视为非虚方法。

答案 1 :(得分:4)

如果您要调用基类实现,请使用base keyword

base.UpdatelastLogin();

将引用转换为基类,实际上不执行任何操作。这就是面向对象编程的美妙之处!你不需要知道什么类型的东西 - 你只需要在一个对象上调用一个方法,这就是该对象的实现方式。

实例化子类后,无论引用的类型如何,该对象的UpdateLastLogin() {{1}}中的条目总是指向子类。