2015-12-21 106 views
3

上週我遇到了一個有趣的問題,我不知道我真正瞭解了following code的多形態性質。我基於我編寫的一些代碼創建了這個示例。多態性質

基本設置

  • 我知道如何訓練動物類「培訓師」。
  • 我使用它作爲基類,並創建了一個知道如何訓練狗的子類「DogTrainer」。
  • 我創建使用超類作爲返回類型的函數指針。
  • 我然後調用該函數獲得子「DogTrainer」的新實例。
  • 我然後調用從函數指針返回的實例的「火車」的方法。
  • 的「列車」方法調用「培訓師」 - 「火車」的方法不是「DogTrainer」 - 如預期

這裏的「火車」的方法是代碼

// 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()); 

現在,如果我使用接口作爲返回類型它確實如預期「IF」我有接口直接標註在「DogTrainer」子類

// Works as expected 
var getITrainer = new Func<ITrainer>(() => new DogTrainer(new Dog())); 
var funcITrainer = getITrainer(); 
Console.WriteLine(funcITrainer.Train()); 

如果我沒有在子類中的接口,其研發工作沒有按預期工作。 See Example

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

您會看到這一行爲是因爲協泛型類型的,不是多態性 –

+1

的,因爲這是「重新實現接口」,因爲它是所謂的語言規範的行爲。我在一個類似的例子[這裏]中描述了它(http://stackoverflow.com/a/25008171/517852)。這與'Func '無關,這隻會使事情不必要地複雜化。 –

+0

感謝您提出問題並附上優質小樣本。正如@mikez指出,這個問題的很大一部分有非常好的答案(已重複鏈接)。第一個示例覆蓋了[什麼是陰影](http://stackoverflow.com/questions/673779/what-is-shadowing)。 –

回答

1

注意的主要部分:這個答案純粹是爲了說明「新」問題,由於在評論不恰當。請不要投票,因爲它沒有完全回答他的問題。從OP的鏈接

樣品:

public class DogTrainer : Trainer, ITrainer 
{ 
    public DogTrainer(IAnimal animal) 
     : base(animal) 
    { } 

    public new string Train() 
    { 
     return $"Speak Ubu, Speak : {Animal.Speak()}"; 
    } 
} 

聲明方法/屬性時不要使用new。讓他們在virtual的基礎上,然後override他們。你正在做的是隱藏在你的基地的方法。

只有在使用該特定類型(DogTrainer)時才能調用new方法。任何向下鑄造到基將調用它的方法即具有聲明爲TrainerITrainer可變工作。

Knowing When to Use Override and New Keywords (C# Programming Guide)

+0

請注意,你回答幾乎與OP所觀察到的相反 - 第二個版本(基於接口)顯然已成功調用DogTrainer.Train而不是基礎版本。 –

+0

是的。猜猜我應該注意到。太多以適應評論塊。 – TyCobb