C# вызывает переопределенные методы подкласса, не зная, что это экземпляр подкласса

У меня есть базовый класс с виртуальным методом и несколько подклассов, которые переопределяют этот метод.

Когда я сталкиваюсь с одним из этих подклассов, я хотел бы вызвать переопределенный метод, но без знания подкласса. Я могу придумать уродливые способы сделать это (проверить значение и применить его), но похоже, что должен быть способ сделать это на языке. Я хочу, чтобы список содержал несколько подклассов в одном списке, иначе, очевидно, я мог бы просто создать список.

Обновлено: исправлен комментарий в коде, который был неправильным, что привело к очень подходящему первому ответу, который я получил :)

Например:

Class Foo 
{
    public virtual printMe()
    {
        Console.Writeline("FOO");
    }
}

Class Bar : Foo 
{
    public override printMe()
    {
        Console.Writeline("BAR");
    }
}

List<Foo> list = new List<Foo>();
// then populate this list with various 'Bar' and other overriden Foos

foreach (Foo foo in list) 
{
    foo.printMe(); // prints FOO.. Would like it to print BAR
} 

как он печатает Foo, если это производный класс, переопределяющий виртуальный метод? Опечатка в вашем примере кода?

Don Cheadle 24.06.2015 18:48
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
1
17 258
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Почему он должен печатать «Foo»? Не в этом цель виртуальных методов. Все дело в том, что производные классы могут изменять способ работы функции без изменения интерфейса. Объект Foo напечатает «Foo», а объект Bar напечатает «Bar». Все остальное было бы неправильно.

Вы абсолютно правы. У меня была ошибка в комментарии во фрагменте, который я изначально опубликовал. Он вызывает метод базового класса, предположительно потому, что не знает, что это экземпляр подкласса.

John Noonan 24.12.2008 02:22

Используйте модификатор новый, чтобы явно скрыть член, унаследованный от базового класса. Чтобы скрыть унаследованный член, объявите его в производном классе с тем же именем и измените его с помощью модификатора new. Это приведет к именно тому поведению, которое вы хотите.

Для получения дополнительной информации перейдите сюда: http://geekswithblogs.net/Mohamed/articles/28613.aspx

Ответ принят как подходящий
class Foo 
{
    public virtual void virtualPrintMe()
    {
        nonVirtualPrintMe();
    }

    public void nonVirtualPrintMe()
    {
        Console.Writeline("FOO");
    }
}

class Bar : Foo 
{
    public override void virtualPrintMe()
    {
        Console.Writeline("BAR");
    }
}

List<Foo> list = new List<Foo>();
// then populate this list with various 'Bar' and other overriden Foos

foreach (Foo foo in list) 
{
    foo.virtualPrintMe(); // prints BAR or FOO
    foo.nonVirtualPrintMe(); // always prints FOO
}

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

John Noonan 24.12.2008 02:28

Чтобы получить желаемое поведение в этой ситуации, вы можете удалить виртуальный объект в базовом классе и использовать новый в подклассе.

Однако, как указал Эд Свангрен, зачем вам это?

Разве нет решения, в котором вы просто приводите объект, который хотите назвать другим:

 foo.printMe(); // prints FOO.. Would like it to print BAR

становится

(Foo)foo.printMe(); // foo can be any derived class of Foo.

Или я упускаю какую-то часть вопроса?

Второй вызовет printMe и попытается преобразовать возвращаемое значение в (Foo). И он возвращается недействительным.

Daniel Earwicker 24.12.2008 03:00

Ах, извините, я пропустил скобки, вторая строка должна быть ((Foo) foo) .printMe (); который должен возвращать foo, когда он приводит объект, а затем выполняет вызов.

JB King 24.12.2008 06:57

Другие вопросы по теме