C# 强制转换到基类,并调用其虚拟方法将导致stackoverflow异常

C# 强制转换到基类,并调用其虚拟方法将导致stackoverflow异常,c#,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 pe

考虑以下代码:

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();
    }
}

如果要调用基类实现,请使用:

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

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

这是因为base关键字禁用了虚拟方法调用,但强制转换没有

让我们把它分解一下:

使用
virtual
s和
override
s,C#有一个算法来找到正确的调用方法。这种算法称为虚拟方法调用

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

但是,当您使用
base
调用重写的base方法时,编译器将该方法(
Person.UpdateLastLogin
)视为非虚拟方法,并且不会对其应用虚拟方法调用和解析

C规范对
覆盖
虚拟
有相当合理的解释。我鼓励您阅读其17.5.3虚拟方法17.5.4覆盖方法部分。具体引用规范:

基本访问将禁用虚拟调用机制,并将基本方法视为非虚拟方法


两者都应该有语法错误,因为UpdatelastLogin!=UpdateLastLogin
((个人)this.UpdateLastLogin()调用它本身而不是基类方法。这是一个递归和堆栈溢出的结果。从技术上讲,如果他在UpdateLastLogin方法的Student类中使用new关键字,他将能够通过使用((Person)this)来执行基方法。UpdateLastLogin()@ToddBowles同意,但鉴于OP目前的理解,我认为这可能有点混乱。
base.UpdatelastLogin();