Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Func的多态性<;T>;在C中#_C#_Polymorphism_Func - Fatal编程技术网

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()}";
    }
}