У меня есть базовый класс с виртуальным методом и несколько подклассов, которые переопределяют этот метод.
Когда я сталкиваюсь с одним из этих подклассов, я хотел бы вызвать переопределенный метод, но без знания подкласса. Я могу придумать уродливые способы сделать это (проверить значение и применить его), но похоже, что должен быть способ сделать это на языке. Я хочу, чтобы список содержал несколько подклассов в одном списке, иначе, очевидно, я мог бы просто создать список.
Обновлено: исправлен комментарий в коде, который был неправильным, что привело к очень подходящему первому ответу, который я получил :)
Например:
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»? Не в этом цель виртуальных методов. Все дело в том, что производные классы могут изменять способ работы функции без изменения интерфейса. Объект Foo напечатает «Foo», а объект Bar напечатает «Bar». Все остальное было бы неправильно.
Вы абсолютно правы. У меня была ошибка в комментарии во фрагменте, который я изначально опубликовал. Он вызывает метод базового класса, предположительно потому, что не знает, что это экземпляр подкласса.
Используйте модификатор новый, чтобы явно скрыть член, унаследованный от базового класса. Чтобы скрыть унаследованный член, объявите его в производном классе с тем же именем и измените его с помощью модификатора 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
}
Это то поведение, которое я хотел, но не получал. Моя проблема заключалась в загрузке старых сериализованных объектов, которые относились к типу старого базового класса, а не к новому подклассу.
Чтобы получить желаемое поведение в этой ситуации, вы можете удалить виртуальный объект в базовом классе и использовать новый в подклассе.
Однако, как указал Эд Свангрен, зачем вам это?
Разве нет решения, в котором вы просто приводите объект, который хотите назвать другим:
foo.printMe(); // prints FOO.. Would like it to print BAR
становится
(Foo)foo.printMe(); // foo can be any derived class of Foo.
Или я упускаю какую-то часть вопроса?
Второй вызовет printMe и попытается преобразовать возвращаемое значение в (Foo). И он возвращается недействительным.
Ах, извините, я пропустил скобки, вторая строка должна быть ((Foo) foo) .printMe (); который должен возвращать foo, когда он приводит объект, а затем выполняет вызов.
как он печатает Foo, если это производный класс, переопределяющий виртуальный метод? Опечатка в вашем примере кода?