Другое поведение перегрузки метода в C#

Я проходил Головоломки C# (http://www.yoda.arachsys.com/csharp/teasers.html) и столкнулся с одним вопросом: каков должен быть вывод этого кода?

class Base
{
    public virtual void Foo(int x)
    {
        Console.WriteLine ("Base.Foo(int)");
    }
}

class Derived : Base
{
    public override void Foo(int x)
    {
        Console.WriteLine ("Derived.Foo(int)");
    }

    public void Foo(object o)
    {
        Console.WriteLine ("Derived.Foo(object)");
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        int i = 10;
        d.Foo(i);  // it prints ("Derived.Foo(object)"
    }
} 

Но если я изменяю код на

class Derived 
{
    public void Foo(int x)
    {
        Console.WriteLine("Derived.Foo(int)");
    }

    public void Foo(object o)
    {
        Console.WriteLine("Derived.Foo(object)");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Derived d = new Derived();
        int i = 10;
        d.Foo(i); // prints  Derived.Foo(int)");

        Console.ReadKey();
    }
}

Я хочу к тому, почему вывод становится измененным, когда мы наследовались по сравнению с не наследованием; почему перегрузка метода ведет себя по-другому в этих двух случаях?

14
задан Michael Myers 12 May 2010 в 18:32
поделиться

3 ответа

Как я указал на странице ответов :

Derived.Foo (объект) печатается - при выборе перегрузки, если существуют любые совместимые методы , объявленные в производном классе, все сигнатуры, объявленные в базовом классе, игнорируются - даже если они переопределяются в том же производном классе!

Другими словами, компилятор просматривает методы, недавно объявленные в наиболее производном классе (на основе типа выражения во время компиляции), и определяет, применимы ли какие-либо из них. Если да, то используется «лучший» из имеющихся. Если ни один из них не подходит, он пробует базовый класс и так далее. Переопределенный метод не считается объявленным в производном классе.

Подробнее см. Разделы 7.4.3 и 7.5.5.1 спецификации C # 3.

Теперь насчет того, почему именно так указано - я не знаю. Для меня имеет смысл, что методы, объявленные в производном классе, имеют приоритет над методами, объявленными в базовом классе, поскольку в противном случае вы столкнетесь с проблемой «хрупкого базового класса» - добавление метода в базовый класс может изменить значение кода с использованием производный класс. Однако, если производный класс переопределяет метод, объявленный в базовом классе, он явно знает об этом, поэтому этот элемент хрупкости не применяется.

19
ответ дан 1 December 2019 в 13:08
поделиться

Он вращается вокруг области видимости. В первой программе void Foo(int i) принадлежит классу Base. Класс Derived просто переопределяет его поведение.

Foo(int i) игнорируется, потому что она "заимствуется" и переопределяется через наследование от класса Base. Если бы Foo(object o) не существовало, то использовалась бы Foo(int i).

Во второй программе вызывается void Foo(int i), потому что она правильно принадлежит классу Derived (т.е. не заимствуется и не переопределяется через наследование) и имеет наилучшее соответствие сигнатуре.

1
ответ дан 1 December 2019 в 13:08
поделиться

Это потому, что сигнатуры методов в производном классе сначала сопоставляются, а затем рассматриваются сигнатуры базового класса. Поэтому, когда вы пытаетесь:

d.Foo(i);

Он пытается сопоставить сигнатуру метода с вашим текущим классом (не с базовым классом). Он находит приемлемое совпадение Foo (object) и больше не рассматривает сигнатуры методов базового класса.

Все дело в том, что компилятор находит соответствующую сигнатуру метода и порядок поиска, который он использует для поиска этих сигнатур.

-Дуг

0
ответ дан 1 December 2019 в 13:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: