C# 使用Func的多态性<;T>;在C中#
上周我遇到了一个有趣的问题,我不确定我是否真正理解了这个问题的多态性。我根据自己编写的一些代码创建了这个示例 基本设置C# 使用Func的多态性<;T>;在C中#,c#,polymorphism,func,C#,Polymorphism,Func,上周我遇到了一个有趣的问题,我不确定我是否真正理解了这个问题的多态性。我根据自己编写的一些代码创建了这个示例 基本设置 我有一个“驯兽师”班,知道如何训练动物 我使用它作为基类,创建了一个子类“DogTrainer”,它只知道如何训练狗 我使用超类作为返回类型创建了一个函数指针 然后,我调用该函数来获取子类“DogTrainer”的新实例 然后调用从函数指针返回的实例的“Train”方法 “训练”方法调用的是“训练师”-“训练”方法,而不是“狗训练师”-“训练”方法 这是密码 // Does
- 我有一个“驯兽师”班,知道如何训练动物李>
- 我使用它作为基类,创建了一个子类“DogTrainer”,它只知道如何训练狗李>
- 我使用超类作为返回类型创建了一个函数指针
- 然后,我调用该函数来获取子类“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());
注意:这个答案纯粹是为了描述“新”问题,因为它不适合评论。请忽略投票,因为投票不能完全回答他的问题。 OP链接中的示例: 声明方法/属性时不要使用
new
。使它们在基座上成为虚拟的,然后覆盖它们。您正在做的是将方法隐藏在您的基础上
在使用特定类型(DogTrainer
)时,您只能调用您的new
方法。对基础的任何向下转换都将调用其方法,即使用声明为Trainer
或ITrainer
的变量
您看到这种行为是因为协变泛型类型,而不是多态性。这是语言规范中所称的“接口重新实现”行为。我在一个类似的例子中描述了它。它与
Func
无关,这只会使问题变得不必要的复杂。感谢您努力将问题与紧凑的示例结合在一起。正如@mikez所指出的,问题的大部分都有很好的答案alread(链接为副本)。第一个样本包含在中。感谢您提供的信息。我知道现在发生了什么。请注意,您的回答几乎与OP观察到的相反-第二个版本(基于接口)显然成功地调用了DogTrainer.Train
,而不是基本版本。正确。我想我应该注意到这一点。太多,无法放入注释块。
// 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());
public class DogTrainerWithNoInterface : Trainer
{
public DogTrainerWithNoInterface(IAnimal animal)
: base(animal)
{ }
public new string Train()
{
return $"Speak Ubu, Speak : {Animal.Speak()}";
}
}
public class DogTrainer : Trainer, ITrainer
{
public DogTrainer(IAnimal animal)
: base(animal)
{ }
public new string Train()
{
return $"Speak Ubu, Speak : {Animal.Speak()}";
}
}