[.NET] new 與 override 關鍵字的差異

Clark Lu
Clark's Tech Blog
Published in
3 min readMar 14, 2019

當不能覆寫 (override) 方法

同事因客制化需求得改寫一既有的類別,遵循 Liskov Substitution Principle,他不打算破壞原本的結構,選擇繼承該類別然後再覆寫 (override) 方法,但此時卻發現父類別的方法沒有宣告修飾詞 virtual,正當我們思考該如何是好,前輩突然提到了一個令人熟悉卻又陌生的關鍵字:new

new 關鍵字

不過我有點懵了,new 這關鍵字我還真少拿來當作方法的修飾詞,小弟經驗不足只好作點功課,並紀錄一下它與 override 的差異。簡單來說,假設我們有一子類別 (ChildClass) 與父類別 (ParentClass) 的方法簽章 (Method Signature) 一樣,而父類別又沒有宣告修飾詞 virtual,此時編譯可以過,但 IDE 會出現警告

代表子類別的方法會隱藏父類別的方法,而這就是加上 new 關鍵字的概念 (有加與沒加的效果一樣,但加上後警告會消失),但注意,它只是隱藏,不是覆寫,因此父類別的方法仍存在,在執行階段 (Run time) 我們仍有可能使用父類別的方法,例如

  1. 若宣告的變數是父類別的資料型態,那繼續呼叫父類別的方法
  2. 若宣告的變數是子類別的資料型態,那優先呼叫子類別的方法,然後才會考慮繼承自父類別的方法

我寫了一個簡單的 Console 來看看使用 new 與 override 之間的差異,其中父類別為 ParentClass, 內含 Method1 及 Method2 兩個方法成員;子類別為 ChildClass,同樣包含 Method1 及 Method2 兩個方法成員,前者使用 new 關鍵字,後者則為 override。而我分別用了三種案例來測試

  1. 變數資料型態為父類別;值也為父類別
  2. 變數資料型態為子類別;值也為子類別
  3. 變數資料型態為父類別;但值為子類別

執行結果如下

  1. 第一個案例很合理,應該不需要多作解釋
  2. 第二個案例的第一個方法要特別注意,由於變數的資料型態屬於子類別,且因為宣告修飾詞 new,隱藏了父類別的方法,會優先執行子類別的方法;有 override 關鍵字的情況則不用多想,變數會直接存取子類別定義的方法
  3. 第三個案例的第一個方法也是要特別注意,由於變數的資料型態仍屬於父類別,且因為宣告修飾詞 new,所以會繼續存取父類別的成員;同樣 override 關鍵字則讓變數直接存取子類別定義的方法
  4. 其實最後我還加入了一個 Special Case,假若我透過父類別的 Proxy1 與 Proxy2 方法分別去執行 Method1 與 Method2,當變數資料型態屬於子類別時,由於子類別本身並沒有 Proxy1 與 Proxy2 的方法存在,因此會繼承自父類別,要特別注意的是,Proxy1 不會存取子類別的 Method1,因為宣告修飾詞 new 的原故,只要執行階段呼叫了父類別的方法,該方法內再呼叫的其他方法也會繼續以父類別為優先;而 override 的情況就沒這麼複雜了,Proxy2 會直接呼叫子類別定義的 Method2

--

--