2011-09-02 81 views
6

我有,我要重寫基類的方法,以稍微改變方法的返回類型的情況。通過稍微改變我的意思是返回,從本來會由基本類型方法返回的對象繼承的對象......其實,一點代碼將使它更容易些......重載方法來改變返回類型

class Program 
{ 
    static void Main(string[] args) 
    { 
     var obj = new ParentClass(); 
     Console.WriteLine("Parent says: " + obj.ShowYourHand()); 

     var obj2 = new ChildClass(); 
     Console.WriteLine("Child says: " + obj2.ShowYourHand()); 

     Console.ReadLine(); 
    } 
} 

public class ParentClass 
{ 
    public string ShowYourHand() 
    { 
     var obj = GetExternalObject(); 
     return obj.ToString(); 
    } 
    protected virtual ExternalObject GetExternalObject() 
    { 
     return new ExternalObject(); 
    } 
} 

public class ChildClass : ParentClass 
{ 
    protected virtual new ExternalObjectStub GetExternalObject() 
    { 
     return new ExternalObjectStub(); 
    } 
} 

public class ExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObject"; 
    } 
} 

public class ExternalObjectStub : ExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObjectStub"; 
    } 
} 

的問題,我有是OBJ2的實例不調用它的GetExternalObject()的版本,而是使用它的父的實現。

我認爲這是因爲在obj的類型預計ExternalObject在父類中的代碼

var obj = GetExternalObject(); 

這樣做。但我明白,C#不能區分基於返回類型的方法。

我知道還有其他問題的解決方案,例如定義IExternalObject,所以請不要太擔心這個問題。我想知道的是,這種想法是什麼阻止了子類GetExternalObject被子類本身調用?

還是我做一些愚蠢的完全? :-)

+0

類似的問題:[C#:重寫返回類型](http://stackoverflow.com/questions/1048884/c-overriding-return-types) –

+0

的[C#:重寫返回類型]可能的複製(HTTPS ://stackoverflow.com/questions/1048884/c-overriding-return-types) –

回答

7

或者我正在做的事情完全愚蠢? :-)

是的,你是。您無法通過覆蓋方法來更改方法的返回類型。無論如何,我不明白它在你的樣本中。只需保留返回類型,並返回新的ExternalObjectStub即可。這工作,因爲ExternalObjectStubExternalObject派生。

通過隱藏與new基礎構件爲你這樣做,通常是一個非常糟糕的主意,因爲它會導致無法在多態的方式使用類更改返回類型。這正是您在這裏遇到的情況:如果保存引用的變量的類型是ParentClass類型,則它調用ParentClass中的方法,即使實例確實是ChildClass類型,也是因爲ChildClass未提供重寫實現GetExternalObject

4

多態性爲你使用它,是不正確的。您需要在您的子類中創建一個隱藏基類實現的新方法,並使用新的返回類型。您不能使用虛擬方法來重載像您一樣的方法。

虛擬方法用於在子類中創建一個方法的不同實現,而不是像您要做的那樣「超載」它。方法

重載是通過改變參數,而不是返回類型來完成。

因此,要麼隱藏子方法中的父方法,要麼使用其他名稱創建方法。對此使用虛擬不起作用。

0

如果你想在子類中返回ExternalObjectStub這ExternalObjectStub應該ExternalObject類

2

得到你應該有你的類返回一個接口,每一個類(ParentClassChildClass)返回接口的實例。您還應該覆蓋ChildClass中的GetExternalObject方法,以便v表指向正確的實施。

此外,當您撥打ShowYourHand時,您的代碼出現錯字 - 您的Main方法引用obj兩次。我改變了這一點,也參考objobj2。這裏是你如何可以與一個界面(和固定在主要的obj錯字)實現這一點:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var obj = new ParentClass(); 
     Console.WriteLine("Parent says: " + obj.ShowYourHand()); 

     var obj2 = new ChildClass(); 
     Console.WriteLine("Child says: " + obj2.ShowYourHand()); 

     Console.ReadLine(); 
    } 
} 

public class ParentClass 
{ 
    public string ShowYourHand() 
    { 
     var obj = this.GetExternalObject(); 
     return obj.ToString(); 
    } 
    protected virtual IExternalObject GetExternalObject() 
    { 
     return new ExternalObject(); 
    } 
} 

public class ChildClass : ParentClass 
{ 
    protected override IExternalObject GetExternalObject() 
    { 
     return new ExternalObjectStub(); 
    } 
} 

public interface IExternalObject { } 

public class ExternalObject : IExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObject"; 
    } 
} 

public class ExternalObjectStub : IExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObjectStub"; 
    } 
} 
2

我不認爲你在所有做任何愚蠢的。我發現自己經常在尋找實現相同模式的方法(Class Foo有一個Bar類型的屬性,Class FooSub:Foo應該能夠將該Property暴露爲類型BarSub:Bar)。

瞭解「新」操作符的一個重要事情是它只隱藏了子類本身的實現。如果子類被轉換回基類,則使用基類的實現。所以你需要確保你有一個「真實」的方法來覆蓋,這樣即使發生這種情況,它仍然會返回正確的類型。

public class ParentClass 
{ 
    public string ShowYourHand() 
    { 
     var obj = GetExternalObject(); 
     return obj.ToString(); 
    } 

    protected ExternalObject GetExternalObject() 
    { 
     return this.RealGetExternalObject(); 
    } 

    protected virtual ExternalObject RealGetExternalObject() 
    { 
     return new ExternalObject(); 
    } 
} 

public class ChildClass : ParentClass 
{ 
    new protected ExternalObjectStub GetExternalObject() 
    { 
     return (ExternalObjectStub)this.RealGetExternalObject(); 
    } 

    protected override ExternalObject RealGetExternalObject() 
    { 
     return new ExternalObjectStub(); 
    } 
}