2008-10-01 42 views
181

什麼是在鹼型「virtual」聲明的方法,然後使用「override」關鍵字覆蓋它在一個子類型,而不是之間的差異,以簡單地使用「new」關鍵字時聲明子類型中的匹配方法?C# - 關鍵字的使用虛擬+倍率與新

+3

[MSDN](http://msdn.microsoft.com/en-us/library/435f1dw2%28v=vs.80%29.aspx)說:「使用`new`會創建一個具有相同名稱的新成員,導致原始成員隱藏,而「覆蓋」擴展了繼承成員的實現「 – AminM 2013-08-14 12:04:31

+0

請參閱http://stackoverflow.com/questions/17717570/why-does-calling-a-method-in-my-derived -class-call-the-base-class-method – 2013-08-20 11:43:44

+0

MSDN - http://msdn.microsoft.com/en-us/library/ms173153.aspx – dayuloli 2014-04-14 10:31:21

回答

163

「new」關鍵字未覆蓋,表示與基類方法無關的新方法。

public class Foo 
{ 
    public bool DoSomething() { return false; } 
} 

public class Bar : Foo 
{ 
    public new bool DoSomething() { return true; } 
} 

public class Test 
{ 
    public static void Main() 
    { 
     Foo test = new Bar(); 
     Console.WriteLine (test.DoSomething()); 
    } 
} 

這將打印假的,如果你使用的覆蓋,將印有真實的。

(從約瑟夫·代格爾採取的基本代碼)

所以,如果你是做真正的多態性你應該總是覆蓋。唯一需要使用「新」的地方是該方法與基類版本沒有任何關係。

+0

你應該修改你的代碼,我已經使靜態方法(這是對於使用「新」關鍵字有效)。但我決定使用實例方法更清晰。 – 2008-10-01 22:16:41

+1

謝謝,我錯過了「靜態」部分。應該注意未來 – albertein 2008-10-01 22:17:57

+1

請注意,Foo test = new Bar()這一行至關重要,metods的新/ override關鍵字決定了將Bar放入Foo變量時調用哪個metod。 – 2015-04-20 13:00:38

18

new關鍵字實際上會創建一個僅存在於該特定類型上的全新成員。

例如

public class Foo 
{ 
    public bool DoSomething() { return false; } 
} 

public class Bar : Foo 
{ 
    public new bool DoSomething() { return true; } 
} 

的方法,存在於這兩種類型。當您使用反射並獲得Bar類型的成員時,實際上會發現兩種方法,名稱爲DoSomething(),看起來完全相同。通過使用new,您可以有效地隱藏基類中的實現,以便在類別從Bar(在我的示例中)派生到base.DoSomething()的方法調用轉到Bar而不是Foo

4

override關鍵字和new關鍵字之間的區別在於前者重寫方法,後者方法隱藏。

退房更多信息,folllowing鏈接...

MSDNOther

40

下面是一些代碼來了解在虛擬和非虛擬方法的行爲差異:

class A 
{ 
    public void foo() 
    { 
     Console.WriteLine("A::foo()"); 
    } 
    public virtual void bar() 
    { 
     Console.WriteLine("A::bar()"); 
    } 
} 

class B : A 
{ 
    public new void foo() 
    { 
     Console.WriteLine("B::foo()"); 
    } 
    public override void bar() 
    { 
     Console.WriteLine("B::bar()"); 
    } 
} 

class Program 
{ 
    static int Main(string[] args) 
    { 
     B b = new B(); 
     A a = b; 
     a.foo(); // Prints A::foo 
     b.foo(); // Prints B::foo 
     a.bar(); // Prints B::bar 
     b.bar(); // Prints B::bar 
     return 0; 
    } 
} 
8

除了技術細節之外,我認爲使用虛擬/覆蓋可以在設計上傳達大量的語義信息。當你聲明一個虛擬的方法時,你表明你期望實現類可能想要提供他們自己的非默認實現。同樣,在基類中省略這一點同樣聲明瞭對於所有實現類都應該滿足缺省方法的期望。同樣,可以使用抽象聲明來強制實現類提供自己的實現。再次,我認爲這會傳達很多關於程序員期望如何使用代碼的信息。如果我正在編寫基礎和實現類,並發現自己使用新的,我會認真重新考慮不要在父項中使方法虛擬並明確聲明我的意圖的決定。

9

虛擬/清除告訴,這兩種方法都涉及編譯器,而且在某些情況下,您會認爲你所呼叫的第一(虛擬)方法實際上它是正確的調用第二個(覆蓋)方法來代替。這是多態性的基礎。

(new SubClass() as BaseClass).VirtualFoo() 

將調用子類的重寫VirtualFoo()方法。

new告訴編譯器,您正在向派生類中添加一個方法,它與基類中的方法具有相同的名稱,但它們彼此沒有關係。

(new SubClass() as BaseClass).NewBar() 

將調用BaseClass的的NewBar()方法,而:

(new SubClass()).NewBar() 

將調用子類的NewBar()方法。

214

我總是覺得這樣的事情有圖片更容易理解:

再次重申,在約瑟夫·代格爾的代碼,

public class Foo 
{ 
    public /*virtual*/ bool DoSomething() { return false; } 
} 

public class Bar : Foo 
{ 
    public /*override or new*/ bool DoSomething() { return true; } 
} 

如果你再這樣調用代碼:

Foo a = new Bar(); 
a.DoSomething(); 

注意:重要的是我們的對象實際上是一個Bar,但我們是將它存儲在變量o F型Foo(這類似於澆鑄)

那麼結果將是如下,這取決於你聲明你的類時使用virtual/overridenew

Virtual/Override Explanation

3
  • new關鍵字是隱藏。 - 意味着你在運行時隱藏了你的方法。輸出將基於基類方法。
  • override重寫。 - 意味着您正在調用派生類方法並引用基類。輸出將基於派生類方法。
1

我的解釋版本來自於使用屬性來幫助理解差異。

override很簡單吧?基礎類型覆蓋父母的。

new也許是誤導(對我而言)。隨着性能更容易理解:

public class Foo 
{ 
    public bool GetSomething => false; 
} 

public class Bar : Foo 
{ 
    public new bool GetSomething => true; 
} 

public static void Main(string[] args) 
{ 
    Foo foo = new Bar(); 
    Console.WriteLine(foo.GetSomething); 

    Bar bar = new Bar(); 
    Console.WriteLine(bar.GetSomething); 
} 

使用調試器,你可以看到,Foo foo2個GetSomething屬性,它實際上有兩個版本的屬性,Foo的和Bar的,要知道哪一個使用,c#「挑選」當前類型的屬性。

如果您想使用Bar的版本,您可能會使用覆蓋或使用Foo foo代替。

Bar bar只有,因爲它完全行爲要進行GetSomething