Полиморфный характер использования Func<T> в C#
Я столкнулся с интересной проблемой на прошлой неделе, и я не уверен, что я действительно понимаю полиморфную природу следующего кода. Я создал этот пример на основе некоторого кода, который я написал.
Базовая настройка
- У меня есть класс "Дрессировщик", который умеет дрессировать животное.
- Я использую это в качестве базового класса и создал подкласс "DogTrainer", который умеет тренировать только собак.
- Я создал указатель на функцию, используя суперкласс в качестве возвращаемого типа.
- Затем я вызываю эту функцию, получая новый экземпляр подкласса "DogTrainer".
- Затем я вызываю метод "Train" экземпляра, возвращенного из указателя функции.
- Метод "Train" вызывает метод "Trainer" - "Train", а не "DogTrainer" - "Train", как ожидалось
Вот код
// Does not work as expected
// Calls the Trainer Train not the DogTrainer Train
var getTrainer = new Func<Trainer>(() => new DogTrainer(new Dog()));
var funcTrainer = getTrainer();
Console.WriteLine(funcTrainer.Train());
Теперь, если я использую интерфейс в качестве возвращаемого типа, он работает как положено. "ЕСЛИ", то у меня есть интерфейс, непосредственно помеченный в подклассе "DogTrainer".
// Works as expected
var getITrainer = new Func<ITrainer>(() => new DogTrainer(new Dog()));
var funcITrainer = getITrainer();
Console.WriteLine(funcITrainer.Train());
Если у меня нет интерфейса в подклассе, он не работает должным образом. См пример
// Does not work as expected
// Calls the Trainer Train not the Dog Trainer Train
var getITrainerWithNoInterface = new Func<ITrainer>(() => new DogTrainerWithNoInterface(new Dog()));
var funcITrainerWithNoInterface = getITrainerWithNoInterface();
Console.WriteLine(funcITrainerWithNoInterface.Train());
Если бы кто-то мог сообщить мне, что мне здесь не хватает, это поведение не то, что я ожидал. Когда я обнаружил эту ошибку в своем коде, я смог ее решить, и вот что я ищу - это "Почему" это происходит.
Вот DogTrainerWithNoInterface
что, вероятно, основная часть головоломки (Trainer:ITrainer
)
public class DogTrainerWithNoInterface : Trainer
{
public DogTrainerWithNoInterface(IAnimal animal)
: base(animal)
{ }
public new string Train()
{
return $"Speak Ubu, Speak : {Animal.Speak()}";
}
}
1 ответ
ПРИМЕЧАНИЕ. Этот ответ предназначен исключительно для описания "новой" проблемы из-за несоответствия в комментарии. Пожалуйста, игнорируйте голосование, так как оно не полностью отвечает на его вопрос.
Образец по ссылке ОП:
public class DogTrainer : Trainer, ITrainer
{
public DogTrainer(IAnimal animal)
: base(animal)
{ }
public new string Train()
{
return $"Speak Ubu, Speak : {Animal.Speak()}";
}
}
Не использовать new
при объявлении методов / свойств. Сделать их virtual
на базе, а затем override
их. То, что вы делаете, это скрытие метода на своей базе.
Вы можете получить только свой new
метод для вызова при работе с этим конкретным типом (DogTrainer
). Любое приведение к базе вызовет его метод, то есть работу с переменной, объявленной как Trainer
или же ITrainer
,