Посмотрел какой-то код в нашей кодовой базе, и я не могу понять, как/почему это даже работает (и не вызывает переполнение стека из-за бесконечной рекурсии). Я вставил несколько эквивалентных кодов ниже: У нас есть виртуальный метод Foo (B), определенный в классе P1 и переопределенный в классе P2. P2 также определяет частный не виртуальный метод Foo (A). B происходит от A. P2:: Foo (B) имеет вызов в конце: Foo (b). Я ожидаю, что это закончится переполнением стека. Однако выход: P2:: Foo Virtual P2:: Foo Частный не виртуальный
Похоже, второй вызов Foo в переопределенном методе - это выбор не виртуального метода Foo в этом случае. При выполнении аналогичных операций в P1 (код uncomment), мы в конечном итоге вызываем Foo бесконечное количество раз через рекурсию.
Вопросы: (наконец!) 1. Почему поведение отличается от исходного виртуального метода и переопределенного метода? Почему один называется сам, а другой вызывает другой метод? 2. Есть ли какой-то порядок предпочтений? Обратите внимание: если мы изменим частный модификатор на публичный, в обоих случаях мы вызываем не виртуальный метод (даже если мы создаем P2 следующим образом: P1 p2 = new P2(); вместо P2 p2 = new P2 ( );) Похоже, что не виртуальная версия является предпочтительной, за исключением случаев, когда она находится внутри определения виртуального метода. Это правда?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
public class P1
{
static void Main(string[] args)
{
B b = new B();
P2 p2 = new P2();
p2.Foo(b);
// Uncomment code to cause infinite recursion
//P1 p1 = new P1();
//p1.Foo(b);
}
private void Foo(A a)
{
Console.WriteLine("P1::Foo Private Non-Virtual");
}
public virtual void Foo(B b)
{
Console.WriteLine("Inside P1::Foo");
// Uncomment code to cause infinite recursion
// Foo(b);
}
}
public class P2 : P1
{
private void Foo(A a)
{
Console.WriteLine("P2::Foo Private Non-Virtual");
}
public override void Foo(B b)
{
Console.WriteLine("P2::Foo Virtual");
Foo(b);
}
}
public class A
{
public int a = 10;
}
public class B : A
{
public int b = 20;
}
}